Initial checkout (vulcano)

Signed-off-by: Alec Ari <neotheuser@ymail.com>
This commit is contained in:
Alec Ari 2014-08-17 10:08:41 -05:00
parent 97d3809ffb
commit dc658435df
1275 changed files with 394449 additions and 0 deletions

74
.gitignore vendored Normal file
View file

@ -0,0 +1,74 @@
# CVS junk
CVS
# Build Files
*.o
*.cmd
*.mod.c
*.ko
*.a
*.lo
*.la
*.swp
*~
base/sched/malloc.c
Module.symvers
modules.order
base/include/asm
base/scripts/rtai-config
base/scripts/rtai-load
rtai_config.h
# Auto-generated files
rtai_config.h.in
configure
aclocal.m4
ltversion.m4
bin/
doc/guide/*.html
addons/drivers/16550A/FORCE
# Generated Makefiles
GNUmakefile.in
GNUmakefile
Makefile
# Config Temp Files
.cfok
.cfchanged
.rtai_config*
addons/rtdm/FORCE
autom4te.cache/
config.log
config.status
libtool
stamp-h1
# Make Temp Files
.deps
.tmp_versions
.libs
# Executables
base/arch/*/calibration/calibrate
base/arch/*/calibration/calibration_helper
base/arch/*/calibration/setsmi
testsuite/*/*/display
testsuite/*/*/latency
testsuite/*/*/preempt
testsuite/*/*/switches
# KConfig Generated files
base/config/kconfig/.config*
base/config/kconfig/.ncurses
base/config/kconfig/lex.zconf.c
base/config/kconfig/libkconfig.so
base/config/kconfig/lxdialog/lxdialog
base/config/kconfig/mconf
base/config/kconfig/zconf.tab.c
# Documentation Files
doc/doxygen/api
doc/docbook/catalog
doc/docbook/custom-stylesheets/xsl/html/chunk.xsl
doc/doxygen/Doxyfile

4300
ChangeLog Normal file

File diff suppressed because it is too large Load diff

131
GNUmakefile.am Normal file
View file

@ -0,0 +1,131 @@
ACLOCAL_AMFLAGS=-I base/config/autoconf
OPTDIRS =
if CONFIG_RTAI_TESTSUITE
OPTDIRS += testsuite
endif
if CONFIG_RTAI_ADDONS
OPTDIRS += addons
endif
if CONFIG_RTAI_LAB
OPTDIRS += rtai-lab
endif
OPTDIRS += rtai-py
SUBDIRS = base @RTAI_MAYBE_DOCDIR@ $(OPTDIRS)
DIST_SUBDIRS = \
@RTAI_MAYBE_DOCDIR@ \
base \
testsuite \
addons \
rtai-lab \
rtai-py
EXTRA_DIST = \
makefile \
README.INSTALL \
README.ISOLCPUS \
README.LINUX_SERVER \
README.LXRT_EXTS_IN_USE \
README.SMI \
@RTAI_MAYBE_SIMDIR@
DISTCLEANFILES = .rtai_config .rtai_config.old .cfok .cfchanged Module.symvers
moduledir = @RTAI_MODULE_DIR@
all-recursive install-recursive: base/GNUmakefile clean-if-reconfigured
base/GNUmakefile: @RTAI_LINUX_DIR@/.config
@echo "*****************************************" ; \
echo "* The Linux configuration has changed *" ; \
echo "* forcing 'make reconfig' ... *" ; \
echo "*****************************************" ; \
$(MAKE) reconfig
clean-if-reconfigured:
@if test -r .cfchanged ; then \
rm -f .cfchanged ; \
echo "****************************************" ; \
echo "* Your RTAI configuration has changed *" ; \
echo "* forcing 'make clean' ... *" ; \
echo "****************************************" ; \
$(MAKE) clean ; \
fi
reconfig xconfig gconfig mconfig menuconfig config oldconfig:
@$(MAKE) -f $(srcdir)/makefile $@ \
srctree=$(srcdir) ARCH=@RTAI_HOST_STRING@ CROSS_COMPILE=@CROSS_COMPILE@
if CONFIG_RTAI_OLD_FASHIONED_BUILD
clean-local:
rm -fr modules .cfchanged
distclean-local:
$(MAKE) -C $(srcdir)/base/config/kconfig \
-f Makefile.kconfig distclean srctree=$(srcdir)
find . -name autom4te.cache | xargs rm -fr
else
clean-local:
rm -f .cfchanged
distclean-local:
test -d $(top_builddir)/base/config && \
$(MAKE) -C $(top_builddir)/base/config/kconfig \
-f @abs_srcdir@/base/config/kconfig/Makefile.kconfig distclean srctree=@abs_srcdir@
endif
install-data-local: .rtai_config
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
$(INSTALL_DATA) .rtai_config $(DESTDIR)$(pkgdatadir)/config-rtai-$(VERSION)
if test -f Module.symvers ; then \
$(INSTALL_DATA) Module.symvers $(DESTDIR)$(moduledir)/Module.symvers ; \
fi
install-exec-local: devices
dist-hook:
$(MAKE) -C $(distdir)/base/config/kconfig \
-f Makefile.kconfig distclean srctree=$(distdir)
rm -fr `find $(distdir) -name CVS`
test -e $(srcdir)/doc || rm -fr $(distdir)/doc
dev devices:
@if test -r $(DESTDIR)/etc/udev/udev.rules ; then \
for f in \
$(srcdir)/base/ipc/shm/rtai_shm.udev \
$(srcdir)/base/ipc/fifos/rtai_fifos.udev \
; do \
b=`basename $$f` ; \
grep -q RTAI:`basename $$b .udev` $(DESTDIR)/etc/udev/udev.rules || \
$$sudo sh -c "( echo ; cat $$f ) >> $(DESTDIR)/etc/udev/udev.rules" ; \
done ; \
elif test -d $(DESTDIR)/etc/udev/rules.d ; then \
for f in \
$(srcdir)/base/ipc/shm/rtai_shm.udev \
$(srcdir)/base/ipc/fifos/rtai_fifos.udev \
; do \
b=`basename $$f` ; \
grep -q RTAI:`basename $$b .udev` $(DESTDIR)/etc/udev/rules.d/99-rtai.rules || \
$$sudo sh -c "( echo ; cat $$f ) >> $(DESTDIR)/etc/udev/rules.d/99-rtai.rules" ; \
done ; \
fi ; \
if test x$(DESTDIR) = x; then \
if test \! "x`type -t sudo`" = x; then sudo=sudo; else sudo=; fi; \
if test \! -c $(DESTDIR)/dev/rtai_shm; then \
$$sudo mknod -m 666 $(DESTDIR)/dev/rtai_shm c 10 254; \
fi; \
for n in `seq 0 9`; do \
f="$(DESTDIR)/dev/rtf$$n"; \
if test \! -c $$f; then \
$$sudo mknod -m 666 $$f c 150 $$n; \
fi; \
done ; \
fi
.PHONY: reconfig xconfig gconfig mconfig menuconfig config oldconfig clean-if-reconfigured dev devices

343
README.INSTALL Normal file
View file

@ -0,0 +1,343 @@
Installing RTAI-3.x
===================
0. RTAI 3.6
================================
RTAI uses only the leanest and fastest RTAI+Linux combination now, i.e. it
dispatches real time interrupts immediately. Moreover within such a scheme
i386 has the possibility of completely avoiding the dispatching of critical
internal timers and interprocessor scheduling interrupts by vectoring them
directly to their handlers. Such an option strongly enhances performances
on low end machines and comes by default. You can disable it while configuring
RTAI though. See the related configuration helper.
What above requires you to patch Linux just with patches found wihin this
distribution.
Notice also that this release is for use with:
- i386,
- x86_64,
- PPC.
On recent distributions, managing udev/sysfs, devices created by following
this installation procedure will disappear at each machine halting. Then they
will be available nomore at the next reboot. RTAI should manage udev/sysfs
support but in case something weird will impede it you can solve your problem
quickly by restoring RTAI devices before running your application. For that
the following short script containing:
------------------------------ cut here -------------------------------------
if test \! -c /dev/rtai_shm; then
mknod -m 666 /dev/rtai_shm c 10 254
fi
for n in `seq 0 9`; do
f=/dev/rtf$n
if test \! -c $f; then
mknod -m 666 $f c 150 $n
fi
done
------------------------------ cut here -------------------------------------
should suffice.
1. How to build
===============
1.1 Standard procedure
----------------------
The RTAI build system is a merge of Linux's Kconfig with
autoconf/automake/libtool. Therefore, you can either build RTAI:
1.1.1 Interactive configuration
-------------------------------
1) Into the source tree like with 24.1.x (your_source_dir ==
your_build_dir). Just run either:
$ make xconfig # (Qt-based)
$ make gconfig # (GTK-based)
$ make menuconfig (dialog-based as in 24.1.x)
Save your configuration, wait for the shell prompt to come back after
the configuration script has fully finished, then run "make".
2) Outside the source tree. From your fresh build directory,
either run:
$ make -f $source_tree/makefile srctree=$source_tree xconfig
$ make -f $source_tree/makefile srctree=$source_tree gconfig
$ make -f $source_tree/makefile srctree=$source_tree menuconfig
If you are using a version of make >= 3.80, then you can even get rid
of the "srctree=$source_tree" setting. The makefile will infere its
value properly.
1.1.2 Non-interactive configuration
-----------------------------------
Since RTAI 3.x has autoconf inside, people needing automatic
non-interactive configuration can directly use the provided GNU
configure script for this purpose. The available configuration
switches can be listed by running ./configure --help. The
RTAI-specific switches are:
--enable-trace Enable trace support
--enable-math Enable math support
--enable-bits Enable bits IPC support
--enable-fifos Enable fifo IPC support
--enable-netrpc Enable netrpc support
--enable-netrpc-rtnet Enable use of RTNet
--enable-sem Enable semaphore support
--enable-msg Enable messaging support
--enable-mbx Enable mailbox support
--enable-tbx Enable typed mailbox support
--enable-mq Enable POSIX-like message queue support
--enable-shm Enable shared memory support
--enable-malloc Enable real-time malloc support
--enable-tasklets Enable tasklets support
--enable-usi Enable user-space interrupt support
--enable-watchdog Enable watchdog support
--enable-leds Enable leds-based debugging support
--enable-sched-lxrt Enable scheduler support without RTAI own ktasks
--enable-ktasks-sched-lxrt Enable scheduler support with RTAI own ktasks
--enable-sched-lock-isr Enable scheduler lock in ISRs
--enable-sched-8254-latency= Set 8254 tuning latency
--enable-sched-apic-latency= Set APIC tuning latency
--enable-sched-lxrt-numslots= Set number of LXRT slots
--enable-cplusplus Build in-kernel C++ support
--enable-comedi-lxrt Enable comedi/LXRT support
--enable-serial Build real-time serial driver
--enable-testsuite Build RTAI testsuite
--enable-rtailab Build RTAI-Lab
--enable-fpu Enable FPU support
--enable-math-c99 Enable math C99 support
--enable-malloc-vmalloc Enable vmalloc support in malloc
--enable-malloc-heap-size Set size of real-time malloc heap
--enable-cpus Enable CPUs
--enable-dox-doc Build Doxygen documentation
--enable-dbx Build Docbook XML documentation.
--enable-dbx-network Try to access Docbook DTD and XSL stylesheets through
network.
--enable-latex-doc Build LaTeX documentation
--enable-verbose-latex Uses LaTeX non-stop mode
--enable-compat Enable compatibility mode
--enable-module-debug Enable debug information in kernel modules
--enable-user-debug Enable debug information in user-space programs
Some configuration targets in base/ can either produce a module,
or be statically linked to the RTAI schedulers. Either pass "m" for
the modular build to their respective --enable-xxx switch, or "y" for
selecting the built-in mode.
1.1.3 Recycling a configuration file
------------------------------------
You can also recycle an existing .rtai_config file from a previous
build by running:
$ cp -rp $old_builddir/.rtai_config \
$new_builddir/.rtai_config
$ cd $new_builddir
$ make -f $source_tree/makefile srctree=$source_tree oldconfig
1.1.4 Selecting alternate compilers
-----------------------------------
Compiler selection must be done at _configuration_ time. One only
needs to pass the right values for the standard environment variables
CC and CXX, respectively for compiling C and C++ source files. In any
case, using a GCC toolchain is mandatory. When unspecified, these
variables's values respectively default to "gcc" and "g++".
WARNING: this selection is not aimed at toggling the cross-compilation
mode on. In order to do so, please refer to 1.2.
Examples:
# Start configuring using the Qt-based GUI with alternate compilers
$ make xconfig CC=/my/favourite/c/compiler CXX=/my/favourite/c++/compiler
# Reconfiguring a previous build tree, changing the compilers on-the-fly.
$ make reconfig CC=/my/favourite/c/compiler CXX=/my/favourite/c++/compiler
# Rebuild all [and optionally install]
$ make [all [install]]
CAVEAT: Since the autoconf-based engine needs to analyze the
compilers's features and crams the CC and CXX values into the
Makefiles it produces, passing CC and CXX variables at build time
simply does _not_ work for the purpose of selecting alternate compiler
toolchains. Again, you need to let the configuration engine know about
these new settings as explained above.
1.2 Cross-compilation support
-----------------------------
Simply add ARCH and CROSS_COMPILE variables as usual to the standard
command lines, e.g.
$ make -f $source_tree/makefile ARCH=arm CROSS_COMPILE=arm-linux-
Names of available architectures can be found under base/arch/*.
1.3 Installing the software
---------------------------
When the standard (or cross-) compilation has finished:
$ cd $builddir
$ make install
Everything needed to use the RTAI distribution will be copied there
out of the build tree. From now on, you should be able to refer to the
installation directory as the root of a complete standalone binary
RTAI distribution.
One may also choose to install the RTAI programs under a temporary
staging tree by passing the standard DESTDIR variable to "make" while
installing. e.g.
$ make install DESTDIR=/mnt/target
will create a standard RTAI hierarchy under /mnt/target, keeping the
original prefix information unmodified. If the installation directory
selected at configuration time was "/usr/realtime", then the command
above will put the RTAI binary distribution under
/mnt/target/usr/realtime.
WARNING: running "make install" is required to run several standard
RTAI programs correctly. RTAI 3.x enforces the actual split between
the source distribution tree, the build tree where RTAI is going to be
compiled, and the final installation directory where RTAI programs can
be run eventually. In any case, you should only rely on the
installation directory contents to run RTAI programs.
NOTE: Do not pay attention to the "*** Warning" messages appearing on
module compilation output. They are harmless and will be fixed later.
1.4 Compiling parts of the tree
-------------------------------
RTAI developers may want to recompile parts of the tree from times to
times. This automake-based build system allows it: just go to the
proper directory level, then issue "make", as usual. This process will
recurse as needed.
The "makefile" (small caps) found in the root source directory is used
to bootstrap the build system when it is about to be configured for
the first time. After the first configuration has been successful, one
just need to run "make xconfig|gconfig|menuconfig|..." as usual.
1.5 Changing the configuration
------------------------------
Each time you want to change your configuration, just run "make
xconfig|gconfig|menuconfig" in your build dir, then "make" (or "make
all").
If you only want to rerun the "configure" script using the current
RTAI configuration, just run "make reconfig", there is no need to
restart any GUI for that.
When invoked for the first time in an empty build directory, the
default "make" goal is "menuconfig" in a regular terminal, or
"xconfig" in an emacs-term.
1.6 Modifying the autotool template files
-----------------------------------------
If you have to change some template files used by any of the autotools
(i.e. Makefile.am, configure.in, acinclude.m4), then you will need the
following pack to rebuild the derived files:
o autoconf 2.59
o automake 1.9.2
o aclocal 1.9.2
o libtool 1.5.8
1.7 Using the integrated calibration tool
-----------------------------------------
RTAI 3.x comes with a brand new calibration tool which should help you
determining if your hardware platform is up to the hard real-time
duties. You can find this tool under $installdir/calibration. Here is
the output of this tool's help message for x86-based platforms:
$ ./calibration --help
OPTIONS:
-h, --help
print usage
-r, --r8254
calibrate 8254 oneshot programming type
-k, --kernel
oneshot latency calibrated for scheduling kernel space tasks
-u, --user
oneshot latency calibrated for scheduling user space tasks
-p <period (us)>, --period <period (us)>
the period of the underlying hard real time task/intr, default 100 (us)
-t <duration (s)>, --time <duration (s)>
set the duration of the requested calibration, default 5 (s)
-c, --cpufreq
calibrate cpu frequency
-a, --apic
calibrate apic frequency
-b, --both
calibrate both apic and cpu frequency
-i, --interrupt
check worst case interrupt locking/contention on your PC
-s<y/n>, --scope<y/n>
toggle parport bit to monitor scheduling on a scope, default y(es)
2. Bootstrapping with vulcano in 7 steps
========================================
>1. patch and build a vanilla Linux kernel tree with the RTAI support as
usual. Patches for x86 are available from
vulcano/base/arch/i386/patches/. Apply only one of them
that matches the Linux kernel version, like this:
$ cd $linux-src-dir
$ patch -p1 < base/arch/$arch/patches/patchfile
>2. $ mkdir $builddir && cd $builddir
>3. $ make -f ../vulcano/makefile srctree=../vulcano
>4. a GUI should pop up, allowing you to configure RTAI:
o default settings should be ok for most platforms
o in the "General" section, set your site values for the RTAI
installation directory (defaults to /usr/realtime) and
Linux kernel tree (defaults to /usr/src/linux).
o save and exit.
--
At this point, you should see the typical output of a GNU configure
script. Your RTAI settings are being used to setup the
autoconf/automake-based build system.
--
>5. $ make install
RTAI will be compiled then installed under the directory you specified
at configuration time (ensure that your shell can write to the
destination directory).
Remember to add $installdir/bin to your shell PATH variable, where
$installdir is your site value for the RTAI installation directory.
--
>6. $ cd $installdir/testsuite/kern/latency
>7. $ ./run
If "sudo" is installed on your box, the application loader script
(rtai-load) will attempt to use it for running privileged commands
(e.g. insmod, rmmod et al.) If sudo is not available, just "su"
manually before running the run script. You should then see the
typical output of the latency calibration program running in kernel
space. Hit ^C to stop it.
--
<rpm@xenomai.org>
12/5/2004

265
README.ISOLCPUS Normal file
View file

@ -0,0 +1,265 @@
*** EXPLOITING CPUs ISOLATION ***
Written by:
Bernhard Pfund <bernhard@chapter7.ch>
and
Paolo Mantegazza <mantegazza@aero.polimi.it>
RTAI can take advantage of the possibility Linux affords to isolate CPUs
from any of its scheduling activity on multi processor (MP) machines.
Contents:
=========
1. Isolcpus
2. IsolCpuMask in RTAI
3. Cpusets & CPU hotplug
4. Example init script
1. Isolcpus
-----------
There should be no better explanation of what it is than the following
excerpts from Linux 'Documentation/kernel-parameters.txt':
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler.
Format:
<cpu number>,...,<cpu number>
or
<cpu number>-<cpu number>
(must be a positive range in ascending order) or a mixture
<cpu number>,...,<cpu number>-<cpu number>
This option can be used to specify one or more CPUs
to isolate from the general SMP balancing and scheduling
algorithms. The only way to move a process onto or off
an "isolated" CPU is via the CPU affinity syscalls.
<cpu number> begins at 0 and the maximum value is
"number of CPUs in system - 1".
This option is the preferred way to isolate CPUs. The
alternative -- manually setting the CPU mask of all
tasks in the system -- can cause problems and
suboptimal load balancer performance.
Add the following to the above, from the very same source:
acpi_irq_nobalance [HW,ACPI]
ACPI will not move active IRQs (default)
default in PIC mode
Irq balancing can be disabled directly at kernel configuration and has little
effect on what will follow. Nonetheless you should prefer to be sure that Linux
does not manipulate hardware related stuff on its own. So if you forgot to
disable irq balancing when you made your kernel there is no need to remake it,
just set it at boot time.
From what above it should be easy to infer that by using "isolcpus" you can
be sure that Linux will have none of its tasks running on the isolated cpus.
That is not entirely true since a few kernel threads and kworkers will have
a copy of each of them repeated and assigned to all of the available CPUs.
It is assumed that they will have very little to do if no interrupt arrives
on the isolated CPUs. Thus if RTAI is able to care avoiding any hard interrupt
on the isolated CPUs they will be fairly well isolated from Linux.
Nevertheless, to further help isolation, RTAI removes any kernel thread and
kworker at the insmoding of its HAL. Even if such an action does not impede
their further dynamic creations there is some evidence that it is useful
anyhow. It would also be possible to block such dynamic creations, an action
that is postponed till more experience is gathered with the use of what above.
To easily check if any following dynamic insertion of something within the
isolated cpus has happened the following might be of help:
cat /proc/*/task/*/status |grep "allowed:" |grep <mask>,
where mask is the mask of what you want either to see not or see.
With what above only Linux rescheduling interrupts should appear on the
isolated CPUs. They are not difficult to block too, but it does not seem
that much more has to be gained by doing so. Therefore, as for what above,
it is momentarily set aside as a possible future TODO action.
Finally, combining all of the above with the possibility of forcing RTAI
enabled Linux process/thread/kthreads to stay on the isolated CPUs the
latter will find themselves processing just RTAI real time stuff, with
a significant reduction of latencies/jitters. In the case of many RTAI
tasks running on the isolated CPUs all issues producing latency/jitter
will still have an effect, but it will be reduced to the least possible,
without any added bus/pipe/cache interference from Linux.
It should be noticed however that there will remain a single interrupt still
managed by Linux, i.e. the one to the local APIC timer. Such an interrupt
will not come from the hardware but from a software inter processor interrupt
(IPI) generated by RTAI to keep Linux happy. It is likely that such an IPI
could be sent only to non isolated CPUs but no testing of such a solution
has been done up to now. The possible change requires just the substitution
of a single line of code but I'm afraid it could damage Linux somehow.
2. IsolCpuMask in RTAI
----------------------
Then what you have to do on the RTAI side is to load the core RTAI HAL module
using something like: "insmod rtai_hal.ko IsolCpusMask=<xxx>", where <xxx>
is the mask of isolated CPUs. Please notice that Linux uses a list if isolated
CPUs while RTAI requires the corresponding mask (I'm lazy and let you do it).
Suppose you have a quadcore system with cores #0 - #3 and want everything but
core #0 to be used by RTAI. In that case, just like in the cpuset example below,
your IsolCpusMask would be 0xE (1110).
What will happen next is that RTAI will divert all of Linux interrupts away
from the isolated CPUs, keeping those requested for RTAI (rt_request_irq)
on the isolated CPUs, without you having to care for it. In such a way there
will be no Linux activity on the isolated CPUs whatsoever and they will remain
within complete RTAI ownership.
Finally it is up to you to exploit such a feature by assigning all of your
tasks to the isolated CPUs, according to your needs, by using:
"rt_task_init_cpuid", "rt_thread_init_cpuid", "rt_task_init_schmod".
Notice that you have also the possibility of further specialising your CPUs
isolation scheme by diverting any real time interrupt you use to a single
specific CPU, or CPU cluster within the isolated CPUs, by using the RTAI
function: rt_assign_irq_to_cpu.
Naturally you can set RTAI "IsolCpusMask" even without setting the Linux
"isolcpus" list, still with some beneficial effects though, for sure, they
will not be as good as with the complete isolation setting described
previously.
3. Cpusets & CPU hotplug
------------------------
If you want to make sure nothing unwanted is _ever_ scheduled on a specific
CPU or core the hotplug system is your friend. (Logically) offlined CPUs are
removed from the Linux scheduler and thus no longer get tasks assigned. Online
again and assigned to a cpuset, RTAI tasks can be scheduled on these CPUs. See
'Documentation/cpusets.txt' and 'Documentation/cgroup.txt'.
Consequently you should inform RTAI about the allowed CPUs (1-3 in the example)
and initialise your tasks accordingly (see section 2).
The example below shows a quadcore CPU partitioned into three sections.
+-Quadcore CPU---------------------+
| |
| +-Production-+ |
| +--------+ | +--------+ | |
| | | | | | | |
| | Core 0 | | | Core 2 | | |
| | | | | | | |
| +--------+ | +--------+ | |
| | | |
| | | |
| +-RTnet------+ | | |
| | +--------+ | | +--------+ | |
| | | | | | | | | |
| | | Core 1 | | | | Core 3 | | |
| | | | | | | | | |
| | +--------+ | | +--------+ | |
| +------------+ +------------+ |
+----------------------------------+
- The root set where only core #0 remains. The kernel and all non real-time
tasks run on that single core.
- The 'RTnet' cpuset on core #1 where all RTDM related tasks are scheduled on.
- The 'Production' cpuset where the real-time controller tasks are executed.
This cpuset has load-balancing enabled, hence tasks assigned to that set are
scheduled on either core #3 or #4 and can be moved within the scheduler domain
if necessary.
Memory isolation is not used in this example and no overlapping sets exist, it's
even actively prevented by using the cpu_exclusive attribute.
By appropriately exploiting both isolation methods illustrated above it is mostly
possible to reduce latencies to single microsec digit figures, especially if the
hard timer periodic mode is adopted.
4. Example init script
----------------------
############# START OF SCRIPT #############
# Environment
MKDIR=/bin/mkdir
MOUNT=/bin/mount
ECHO=/bin/echo
CPUSET=/dev/cpuset
DEVICES=/sys/devices/system/cpu
SLEEP=/bin/sleep
NAME=cpuset
reset_cpus()
{
# Shutdown CPU cores 1 - 3
$ECHO 0 > $DEVICES/cpu1/online
$ECHO 0 > $DEVICES/cpu2/online
$ECHO 0 > $DEVICES/cpu3/online
# Noop
$SLEEP 1
# Enable CPU cores 1 - 3
$ECHO 1 > $DEVICES/cpu1/online
$ECHO 1 > $DEVICES/cpu2/online
$ECHO 1 > $DEVICES/cpu3/online
}
mount_cpuset()
{
$MKDIR $CPUSET
# Configure the root set
if [ -e $CPUSET ]; then
$MOUNT -t cgroup -ocpuset cpuset $CPUSET
# Disable load balancing in the root set
$ECHO 0 > $CPUSET/cpuset.sched_load_balance
fi
}
create_rtnet_set()
{
# Configure the RTnet cpuset
if [ -e $CPUSET ]; then
$MKDIR $CPUSET/rtnet
$ECHO 1 > $CPUSET/rtnet/cpuset.cpus
$ECHO 1 > $CPUSET/rtnet/cpuset.cpu_exclusive
# Disable load balancing in the rtnet set
$ECHO 0 > $CPUSET/rtnet/cpuset.sched_load_balance
fi
}
create_production_set()
{
# Configure the production cpuset
if [ -e $CPUSET ]; then
$MKDIR $CPUSET/production
$ECHO 2,3 > $CPUSET/production/cpuset.cpus
$ECHO 1 > $CPUSET/production/cpuset.cpu_exclusive
# Enable load balancing in the production set
$ECHO 1 > $CPUSET/production/cpuset.sched_load_balance
fi
}
case "$1" in
start)
reset_cpus
mount_cpuset
create_rtnet_set
create_production_set
;;
stop)
reset_cpus
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop}" >&2
exit 2
;;
esac
exit 0
############# END OF SCRIPT #############

186
README.LINUX_SERVER Normal file
View file

@ -0,0 +1,186 @@
 *** SERVING LINUX SYSCALLS IN RTAI HARD REAL TIME MODE ***
The default RTAI way of dealing with Linux syscalls done while in hard real
time consists in moving a task wanting to use Linux back to soft mode,
recovering it to hard real time again, as soon as possible, afterward. See the
related RTAI configuration helper for an explanation of the different available
modes to implement the "as soon as possible" above on various architectures.
This README documents possible alternative ways to access Linux services from
hard real time RTAI applications in user space. Such a support is based on the
creation of a general purpose server thread that takes over Linux requests.
It must be noticed that if Linux is to be used synchronously at the very moment
Linux is called the task becomes timed by Linux, wherever a Linux server is
used or not. So hard real time constraints cannot be satisfied anyhow. The use
of a Linux server has an advantage though. In fact it takes just two context
switches, in place of the four used by hard-soft-hard transitions. Moreover it
ensures that RTAI returns to hard real time immediately after the Linux syscall
has finished while, if the architecture does not support the immediate Linux
syscall mode reliably for all Linux syscalls, there will be the need to wait
for a call to an RTAI function to go back in RTAI hard real time fully. That
will add even far more latencies when a hard RTAI task does some processing
for a significant amount of time after the Linux syscall, without using any
RTAI service. So, provided it is allowed loosing real time, installing a
synchronous server might be the best way to interact with Linux anyhow.
There are however instances in which Linux can be used asynchronously. In
such cases RTAI hard real time tasks might use Linux without loosing hard
real time determinism. Such a capability can be implemented in many ways,
the one chosen by RTAI is based on a buffering of async Linux syscalls mated
either to an optional callback function or to inquiry mechanisms to help
implementing any user own async call policy. Beware of not reusing read/write
data buffers made available to async calls though.
If you do not want, or cannot, either inquire for or check async terminations,
to avoid running the risk of reusing an yet unserved buffer, use RTAI dynamic
memory or SCB to allocate them in real time, freeing them afterward, possibly
with the help of a support callback function.
Async support is a bit tricky but, provided one cares of what said above, it
should work always when Linux syscalls arguments are fully contained in the
passed registers structure. That is not the case for a few Linux syscalls that
are multiplexed within a single framework, whereas libc can end in building a
hidden object on the stack, so that it is not assured it will be available at
the time the server uses it. On some archs a notable example of that is the
socketcall, but RTAI should already care of it appropriately. There remain
nonetheless the chance of other instances to be cared as well. So beware that
some async calls might not work with a few Linux services yet, in which case
you should let us know about it for a possible fix.
Just to mention another typical care to be taken we notice that printf might
work as it is but it will often crash. So the safe way to printf is as follows:
- sprintf(buffer, format, args, ....);
- write(STDOUT_FILENO, buffer, strlen(buffer));
Provided the socketcall has been intercepted well you should be able to do many
IO operations asynchronously, e.g.: dumping data directly to disk, Linux ipcs
and POSIX mq, fifos, pipes, serial and networked communications etc. etc.
In many applications one often requires RTAI specific IO drivers just to avoid
loosing real time for communications with non real time support/interface
processes and tasks. The async server should be of much help in such cases by
letting you use standard Linux, with the ensuing advantage of not needing any
special hard real time driver.
Clearly what above does not impede you to set up your own async server to
which your hard real time task can be connected by using RTAI non blocking
communication functions, i.e. those ending with "_if". So the choice of the
most viable solution is left to you.
How it works
------------
By using the functions described below a server thread is created that will
block waiting for parent task requests to Linux. Whenever the RTAI scheduler
intercepts a Linux syscall in hard real time mode it passes it to the server
thread and:
- remains waiting for its execution if in sync mode;
- returns immediately if in async mode.
The server carries out the syscall and:
- resumes the hard real time parent, returning what returned by Linux, if in
sync mode:
- calls a callback function, if one has been made available, in async mode,
returning an identifier.
As said in sync mode real time is lost, but there will be two task switches per
Linux service request only, while there will be four if no sync server is used.
In async mode there is no need for any task switch, as the server will execute
in soft mode when there will be no RTAI real time activity any more.
The need of passing syscall data to the server is responsible for most of the
penalty incurred by using a Linux server.
Let's stress once more that this is a far better alternative way to what the
RTAI scheduler will have to do anyhow, i.e. make you soft and recover hard mode
at the next RTAI proper service call, which will require four task switches,
keeping you in Linux hands from the Linux syscall till an RTAI function is
called again.
With a server instead you will stay soft just either till Linux has finished
servicing your request, when in sync mode, or kept working in real time, when
in async mode.
API Functions prototypes
------------------------
The available functions are:
- void *rt_create_linux_syscall_server(RT_TASK *task, int mode, void
(*callback_fun)(long, long), int nr_bufd_async_calls);
create a Linux syscall server for task, a NULL task means the current one; a
non NULL return is the handle allowing you to link to the server for any
further management request, see functions below, NULL indicates a failure in
setting the server up; a NULL callback_fun is allowed. It will operate
according to mode setting, either SYNC_LINUX_SYSCALL or ASYNC_LINUX_SYSCALL.
Beware of using an appropriate nr_bufd_async_calls. If async requests overrun
the latest will be discarded till some space is available again.
If a server exists already it is terminated and a new one replaces it.
- void rt_destroy_linux_syscall(RT_TASK *task);
destroy the linux_syscall_server of task, if NULL use the current task.
- void *rt_sync_async_linux_syscall_server_create(RT_TASK *task, int mode,
void (*callback_fun)(long, long), int nr_bufd_async_calls);
legacy interface, the same as:
rt_create_linux_syscall_server(task, mode, callback_fun, nr_bufd_async_calls).
- void *rt_linux_syscall_server_create(RT_TASK *task);
legacy call, the same as:
rt_create_linux_syscall_server(task, SYNC_LINUX_SYSCALL, NULL, 1).
Notice that in sync mode Linux functions will return their usual values while
that is not possible in async mode and what returned is an identifier, id, of
that specific async call, a negative id meaning the call was not satisfied
because of a buffer overrun. When <= 0 ids can be used for monitoring async
calls execution, as explained below.
- int rt_set_linux_syscall_mode(int mode, void (*callback_fun)(long, long);
to both switch between sync and async mode and change the call back function.
It returns EINVAL if there is no server or the mode setting is not correct.
Notice that this is a legacy call, you'd better use:
- int rt_linux_syscall_mode(struct linux_syscalls_list *syscalls, int mode);
to switch between sync and async mode; syscalls is the handle returned by
rt_sync_async_linux_syscall_server_create; mode can be: SYNC_LINUX_SYSCALL,
ASYNC_LINUX_SYSCALL, LINUX_SYSCALL_GET_MODE.
The function returns the previous mode and LINUX_SYSCALL_GET_MODE can be used
to just inquire for it, in which case mode is discarded. EINVAL is returned if
syscalls is not a valid pointer.
- void *rt_linux_syscall_cbfun(struct linux_syscalls_list *syscalls, void (*cbfun)(long, long));
to change the callback function; syscalls is the handle returned by
rt_sync_async_linux_syscall_server_create; cbfun can be either a NULL, no
callback will be used, a pointer to a true callback function,
LINUX_SYSCALL_GET_CALLBACK.
The function returns the pointer to the previous callback function and
LINUX_SYSCALL_GET_CALLBACK can be used to just inquire for it. EINVAL is
returned if syscall is not a valid pointer
The callback function afford a notification control mechanism for async calls.
An alternative way to monitor async calls execution is given by the following
functions:
- int rt_linux_syscall_status(struct linux_syscalls_list *syscalls, int id, int *retval);
syscalls is the handle returned from rt_sync_async_linux_syscall_server_create;
id is the value returned by the call to Linux, retval is a pointer to an int
that will receive the value returned by Linux after executing the related
service.
It returns:
- EINVAL if syscalls is not a valid pointer or id < 0
- ENOENT if no id is found, meaning the function has been overwritten;
- ECANCELED when the function has call has been explicitly canceled by the
user;
- EINPROGRESS when the function is pending waiting for execution;
- 0 when the function has been executed, in such a case retval, if not NULL,
will receive the value returned by Linux.
- int rt_linux_syscall_cancel(struct linux_syscalls_list *syscalls, int id);
Syscalls is the handle returned from rt_sync_async_linux_syscall_server_create;
id is the value returned by the call to Linux.
It returns:
- EINVAL if syscalls is not a valid pointer or id < 0
- ENOENT if no id is found, meaning the function has been overwritten;
- -id when the function has been executed already;
- 0 if the function has been successfully canceled.
Examples
-------
They are in RTAI "showroom" CVS: linux_server and printer_server.
Paolo.

57
README.LXRT_EXTS_IN_USE Normal file
View file

@ -0,0 +1,57 @@
User space RTAI syscalls have 16 extensions slots. They allow any user to
extend RTAI with her/his own user space callable APIs without touching
RTAI itself. For the most efficient inline usage of any extension user slots
must be assigned statically. RTAI itself uses a few extension slots for some
of its native addons, as listed below.
Those already used by modules found in this distributions are:
0 - RTAI itself (hardwired),
1 - tasklets (hardwired),
2 - watchdog (hardwired),
9 - comedi,
10 - fifos,
14 - serial,
15 - rtdm.
So you can reuse the above slots only if you are not using the related modules
found in this distribution. In any case check the value returned by:
set_rt_fun_ext_index.
N.B. "(hardwired)" above means they are assumed as basic RTAI proper extensions.
Nonetheless extension 1 and 2 do check if they can install into their hardwired
slots, exiting their installation in error if they cannot.
So you can make the related slot yours if neither tasklets nor watchdog are
being used by your applications; __NEVER__ USE 0 though.
In any case you'd better choose the other many free slots available to avoid
any trouble.
If in doubt about slots engaged already use something like the following piece
of code in your extension module to discover them:
#define MAX_LXRT_EXT 16
do {
int i;
struct rt_fun_entry fun;
for (i = 0; i < MAX_LXRT_EXT; i++) {
if (set_rt_fun_ext_index(&fun, i) < 0) {
rt_printk("< LXRT SLOT %d ENGAGED >\n", i);
} else {
reset_rt_fun_ext_index(&fun, i);
}
}
} while (0);
It has been already said above but, if you are still asking yourself why there
is a forced staticalization of LXRT extension slots assignment, while it
would be trivial to have functions to get/free slots dynamically, think about
efficiency first, especially if direct (eager in the related RTAI config
caption) inlining is used.
WARNING
If you intend to use Linux i386 with REGPARM configured notice that all your
functions callable from user space must be prefixed with "RTAI_SYSCALL_MODE".
In such a way they will be usable both with and without REGPARM. If you do
not do so then avoid configuring REGPARM for Linux, which is not possible from
2.6.20 onward, where REGPARM is the only way to operate and so it is an option
no more.

1
README.SMI Normal file
View file

@ -0,0 +1 @@
See base/arch/i386/calibration/README.SMI

14
README.maintainer Normal file
View file

@ -0,0 +1,14 @@
- change version in:
- configure.in
- base/arch/*/defconfig (no more)
- base/arch/*/Kconfig (no more)
- cvs tag -F RTAI_X_Y
NOTE: base/arch/m68k contains files whose path is too long for the default
command generated by automake/autoconf for the tar command, which uses
the (obsolete) -o option for compatibility with legacy versions.
s/chof/chf/
This option, right now, needs to be manually removed from the generated
GNUMakefile in the root of the build tree.

18
addons/GNUmakefile.am Normal file
View file

@ -0,0 +1,18 @@
OPTDIRS =
if CONFIG_RTAI_CPLUSPLUS
OPTDIRS += cpp
endif
if CONFIG_RTAI_RTDM
OPTDIRS += rtdm
endif
if CONFIG_RTAI_COMEDI_LXRT
OPTDIRS += comedi
endif
OPTDIRS += drivers
SUBDIRS = $(OPTDIRS)

View file

@ -0,0 +1,59 @@
moduledir = @RTAI_MODULE_DIR@
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
libmodule_a_SOURCES = kcomedi-module.c
include_HEADERS = rtai_comedi.h
if CONFIG_KBUILD
rtai_comedi.ko: @RTAI_KBUILD_ENV@
rtai_comedi.ko: $(libmodule_a_SOURCES)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ rtai_extradef="-I@COMEDI_DIR@/include" \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
else
noinst_LIBRARIES = libmodule.a
libmodule_a_AR = $(CROSS_COMPILE)ar cru
libmodule_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include \
-I@COMEDI_DIR@/include
rtai_comedi.o: libmodule.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: rtai_comedi$(modext)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: rtai_comedi$(modext)
$(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $< $(DESTDIR)$(moduledir)
lib_LIBRARIES = libkcomedilxrt.a
libkcomedilxrt_a_CFLAGS = \
@RTAI_REAL_USER_CFLAGS@ \
-DCONFIG_RTAI_LXRT_INLINE=0 \
-D_GNU_SOURCE -D_REENTRANT \
-I$(top_srcdir)/base/include \
-I../../base/include \
-I@COMEDI_DIR@/include
libkcomedilxrt_a_SOURCES = kcomedi.c
libkcomedilxrt_a_AR = $(CROSS_COMPILE)ar cru
EXTRA_DIST = Makefile.kbuild patchlinuxcomedi

View file

@ -0,0 +1,10 @@
EXTRA_CFLAGS += -I$(rtai_srctree)/base/include \
-I$(rtai_srcdir) \
-I$(src)/../../base/include \
-I$(src)/../.. \
$(rtai_extradef) \
-D__IN_RTAI__
obj-m += rtai_comedi.o
rtai_comedi-objs := $(rtai_objs)

243
addons/comedi/README Normal file
View file

@ -0,0 +1,243 @@
<*> RTAI_KCOMEDI IN USER SPACE <*>
This release of RTAI is intended to be mated to the latest COMEDI git
repository, as found at: www.comedi.org. Warm thanks are due to Frank Mori Hess
<fmhess@users.sourceforge.net> and Ian Abbott <abbotti@mev.co.uk>, for their
help and suggestions about stabilizing on such a choice, taking the chance
of these thanks to recall also the one who initiated it all: David Schleef.
This porting of KCOMEDI to user space is done using the standard extension
feature of LXRT and makes KCOMEDI symmetrically usable in kernel and user
space within RTAI, in soft/hard real time. To use KCOMEDI in user space you
have just to know how to use it in kernel space. So whatever space you are
going to work in it will be mostly the same.
There are nonetheless a few points forbidding the above statements to be
unconditionally true. The related clashes are resolved with functions
prefixed with "rt_".
One is related to a couple of name returning functions:
"comedi_get_driver_name" and "comedi_get_board_name".
In kernel space the requested name is simply got by returning a pointer to
a directly addressable global namestring, which wont work in user space.
So there is the need of copying the namestring available in kernel space to
user space, therefore the calling convention must be changed. Then the
following two aliases, usable both in kernel and user space, have been made
available:
void *rt_comedi_get_driver_name(unsigned int dev, char *name);
void *rt_comedi_get_board_name(unsigned int dev, char *name);
On success both of them return the address "name", at which the actual name
is copied, NULL otherwise.
The solution of the above problem is simple and, almost, compulsory.
In fact the only real problem to be solved for a symmetric approach to
KCOMEDI in kernel and user space has been the use of a callback function
in user space for which a fairly general usage scheme has been devised.
The callback method made available is based on using a built in callback
function that triggers an rt_task_resume and allows returning back to the
user the important unsigned long mask, made available by the standard KCOMEDI
callback service as its first argument.
The related support comes from using the following function, not needed but
available in kernel space also (in case you'll like it):
int rt_comedi_register_callback(void *dev, unsigned int subdev, unsigned int
mask, int (*callback)(unsigned int, void *), void *task);
- the first 3 arguments are the same as in "comedi_register_callback", while
"callback" is discarded and "task" is the pointer to an RTAI task that
waits for asynchronous events to happen. NULL can be used in place of
"task", if it is the current one, in which case RTAI can care of setting
it appropriately.
For compatibility reasons the standard COMEDI:
int comedi_register_callback(unsigned int minor, unsigned int subdev,
unsigned int mask, int (*cb)(unsigned int, void *), void *arg);
is also available in user space in the form of a macro that redirects it to
"rt_comedi_register_callback", setting "cb" to NULL while "arg" should be
assigned either the pointer to the task to be used or NULL.
As said there is clearly no need for anything similar in kernel space, as the
original COMEDI function is available directly, but the user space approach,
with its canned solution, might prove viable and easier to use in kernel space
also.
After the COMEDI callback has been initialized a user can synchronize its
application with COMEDI asynchronous events by using any of the following
functions, usable in kernel space also naturally:
long rt_comedi_wait(unsigned int *cbmask);
- this function waits for the callback unconditionally; cbmask is a compulsory
non NULL pointer to a variable that will receive the callback mask of the
events that triggered it.
long rt_comedi_wait_if(unsigned int *cbmask);
- this function is equivalent to "rt_comedi_wait" but returns immediately
if no COMEDI event has been signaled yet. Useful for polling COMEDI events,
through the returned mask, without blocking.
long rt_comedi_wait_until(RTIME until, unsigned int *cbmask);
- this function is equivalent to "rt_comedi_wait" but features an absolute
timeout, given by "until".
unsigned long rt_comedi_wait_timed(RTIME delay, unsigned int *cbmask);
- this function is equivalent to "rt_comedi_wait" but features a relative
timeout, given by "delay".
- The returned value can be:
- 0 if waiting for a callback succeeded,
- a negative number, in which case its absolute value indicates wait overruns;
- an RTAI error if >= RTE_BASE.
It is likely that the illustrated callback scheme and synchronization is
better exploited by using a thread acting as an asynchronous COMEDI events
manager in hard real time. However it is by no means the only way as the
above wait functions can be used anywhere and rt_comedi_wait_if makes it
possible an easy implementation of a polling scheme.
In fact async wait read functions embed comedi_waits for an easier and more
compact use of async command readings, see below.
Notice that rt_comedi_wait_if is provided to comply with the standard RTAI
synchronizing functions scheme: unconditional, if, until, timed.
An alternative way is provided through the standard KCOMEDI async data polling,
i.e.: comedi_poll.
Once woken up from wait one can call:
long rt_comedi_command_data_read (void *dev, unsigned int subdev, long nchans,
lsampl_t *data);
to get "nchans" channels in "data". Notice that data are read only if "nchans"
elements are available, nothing being done otherwise. Such a condition can
be checked through the returned value, which will be the number of available
read channels data. So a return value less than "nchans" will mean nothing has
been read. The return value can be RTE_OBJINV also, in the case of dev/subdev
being wrong.
It is believed that imposing that either "nchans" data or nothing is available
is the most appropriate real time mechanism, as it is better to let the user
decide what to do in place of waiting on a rescheduling by default. In fact,
after an appropriate wait function is called, missing data might be a error
to care of. If it is not so then, by exploiting the available wait functions,
the user has plenty of opportunities to implement her/his own best policy.
If one notices a bias toward sampling data for digital control systems, versus
pure data acquisition, (s)he is right, absolutely. See below for something
reinforcing such a bias. Despite such an attitude nothing is lost in the case
of pure data acquisition.
A typical code sample could be:
long mask, avbs;
.
comedi_register_callback(dev, subdev, COMEDI_CB_EOS, NULL, task);
.
if (rt_comedi_wait_timed(nano2count(TIMEOUT), &mask) != 0) {
printf("waiting for async data failed\n");
}
.
if (mask & COMEDI_CB_EOS) {
if ((avbs = rt_comedi_command_data_read(dev, subdev, NCHAN, data)) != NCHAN) {
printf("only %ld channels data available in place of %d, nothing read\n", avbs, NCHAN);
}
.
}
.
Calling an rt_comedi_wait followed by rt_comedi_command_data_read is OK and
let the user do whatever check (s)he needs. Nonetheless, when working in user
space, it has the disadvantage of taking two trips to kernel space. Since what
is mostly required is a successful rt_comedi_wait with a mask containing the
appropriate user expected callback mask the two calls can be unified. Such a
scheme is mostly useful in a digital controller, whereas a single call paces
its action in such a way that at each sampling time one is ready to apply
her/his control law on the available channels samples immediately.
To that end RTAI makes available the following:
long rt_comedi_command_data_wread(void *dev, unsigned int subdev, long nchans, lsampl_t *data, long *mask);
long rt_comedi_command_data_wread_if(void *dev, unsigned int subdev, long nchans, lsampl_t *data, long *mask);
long rt_comedi_command_data_wread_until (void *dev, unsigned int subdev, long nchans, lsampl_t *data, RTIME until, long *mask);
long rt_comedi_command_data_wread_timed(void *dev, unsigned int subdev, long nchans, lsampl_t *data, RTIME delay, long *mask);
whose arguments are the union of the previous calls, with "mask" containing
the event flags that must be found set in the callback mask returned by COMEDI
callbacks.
The previous code snippet would become:
long mask, avbs;
.
comedi_register_callback(dev, subdev, COMEDI_CB_EOS, NULL, task);
.
mask = COMEDI_CB_EOS;
if ((avbs = rt_comedi_command_data_wread_timed(dev, subdev, NCHAN, data, nano2count(TIMEOUT), &mask)) != NCHAN) {
printf("only %ld channels data available in place of %d, or an error occured, nothing read\n", avbs, NCHAN);
}
.
There are examples in RTAI "showroom" CVS, "user/comedi" that should help
in depicting the use of the above explained extensions.
The async write mate of async data reading is the following:
long rt_comedi_command_data_write(void *dev, unsigned int subdev, long nchans, lsampl_t *data);
arguments and return values being the same of rt_comedi_command_data_read.
Another useful service is:
int rt_comedi_trigger(void *dev, unsigned int subdev);
It is based on an easy set up of a wrapper, using the appropriate
comedi_do_insn for the actual triggering action.
Finally the function:
int rt_comedi_do_insnlist(void *dev, comedi_insnlist *ilist);
has been added, symmetrically in kernel/user space as usual.
It is an exact image of its parent:
int comedi_do_insnlist(void *dev, comedi_insnlist *list);
which is not available in KCOMEDI. That's why we prefixed it with an "rt_".
The simple reason of it being missed in kernel space is because it will add
just the overhead of one call more to obtain something that a user can have
directly by executing repeated "comedi_do_insn" in her/his own way. From user
space instead the overhead of calling "comedi_do_insn" many times could
be much more significant, so it might help in having the possibility of
executing a whole set of instructions in a single shot to kernel space only.
The following macros can be used to avoid remembering the instruction fields:
#define BUILD_AREAD_INSN(insn, subdev, data, nd, chan, arange, aref)
to set up an instruction for analog input;
#define BUILD_AWRITE_INSN(insn, subdev, data, nd, chan, arange, aref)
to set up an instruction for analog output;
#define BUILD_DIO_INSN(insn, subdev, data, nd)
to set up an instruction for digital input/output.
A final warning: all KCOMEDI functions are executed without the comedi_lock
being activated. That's because it adds some, albeit negligible on nowadays
machines, overhead and because in control systems it is rare to have possible
conflicting acquisitions shared among more tasks. If a locked execution is
needed nonetheless, then the user can explicitly configure RTAI to do that,
in which case it will be applied to all services. Being "comedi_lock" and
"comedi_unlock" available to the user anyhow, (s)he is free to apply them
explicitly whenever (s)he has decided to not configure them by default.
"The Comedi Players"
<*> USING RTAI_KCOMEDI FOR DISTRIBUTED DATA ACQUISITION <*>
Distributed data acquisition is obtained by simply using the standard NETRPC
specification, i.e.:
- use just the name of any already available function substituting either
"rt_..." with "RT_..." or, as for the direct use of COMEDI APIs names.
prefixing "RT_" in front of them
- add two initial arguments more, i.e. the "node" of and the "port" on the
remote machine that will execute "RT_..." functions.
For example:
rt_comedi_do_insnlist(dev, ilist);
becomes:
RT_comedi_do_insnlist(dev, ilist);
while:
comedi_do_insn(dev, insn);
becomes:
RT_comedi_do_insn(dev, insn);
as well.
Naturally the remote node, where the data acquisition hardware is installed,
must have insmoded: all of the modules needed for COMEDI, rtai_netrpc and
rtai_comedi.
There are examples in RTAI "showroom" CVS, "user/comedi" that should help
in depicting the use of the above explained extensions.
Paolo Mantegazza

View file

@ -0,0 +1,741 @@
/*
* Copyright (C) 2006 Thomas Leibner (leibner@t-online.de) (first complete writeup)
* 2002 David Schleef (ds@schleef.org) (COMEDI master)
* 2002 Lorenzo Dozio (dozio@aero.polimi.it) (made it all work)
* 2006 Roberto Bucher <roberto.bucher@supsi.ch> (upgrade)
* 2002-2010 Paolo Mantegazza (mantegazza@aero.polimi.it) (hints/support)
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* This is the module to support using COMEDI in hard real time within RTAI.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <rtai_schedcore.h>
#include <rtai_sched.h>
#include <rtai_lxrt.h>
#include <rtai_shm.h>
#include <rtai_msg.h>
#include <rtai_comedi.h>
#define MODULE_NAME "rtai_comedi.o"
MODULE_DESCRIPTION("RTAI LXRT binding for COMEDI kcomedilib");
MODULE_AUTHOR("The Comedi Players");
MODULE_LICENSE("GPL");
#ifdef CONFIG_RTAI_USE_COMEDI_LOCK
#define RTAI_COMEDI_LOCK(dev, subdev) \
do { comedi_lock(dev, subdev); } while (0)
#define RTAI_COMEDI_UNLOCK(dev, subdev) \
do { comedi_unlock(dev, subdev); } while (0)
#else
#define RTAI_COMEDI_LOCK(dev, subdev) do { } while (0)
#define RTAI_COMEDI_UNLOCK(dev, subdev) do { } while (0)
#endif
#define KSPACE(adr) ((unsigned long)adr > PAGE_OFFSET)
static int rtai_comedi_callback(unsigned int, RT_TASK *) __attribute__ ((__unused__));
static int rtai_comedi_callback(unsigned int val, RT_TASK *task)
{
if (task->magic == RT_TASK_MAGIC) {
task->resumsg = val;
rt_task_resume(task);
}
return 0;
}
static RTAI_SYSCALL_MODE void *_comedi_open(const char *filename)
{
return comedi_open(filename);
}
static RTAI_SYSCALL_MODE int _comedi_close(void *dev)
{
return comedi_close(dev);
}
static RTAI_SYSCALL_MODE int _comedi_lock(void *dev, unsigned int subdev)
{
return comedi_lock(dev, subdev);
}
static RTAI_SYSCALL_MODE int _comedi_unlock(void *dev, unsigned int subdev)
{
return comedi_unlock(dev, subdev);
}
static RTAI_SYSCALL_MODE int _comedi_cancel(void *dev, unsigned int subdev)
{
RTAI_COMEDI_LOCK(dev, subdev);
return comedi_cancel(dev, subdev);
RTAI_COMEDI_UNLOCK(dev, subdev);
}
RTAI_SYSCALL_MODE int rt_comedi_register_callback(void *dev, unsigned int subdev, unsigned int mask, int (*callback)(unsigned int, void *), void *task)
{
int retval;
if (task == NULL) {
task = rt_whoami();
}
((RT_TASK *)task)->resumsg = 0;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_register_callback(dev, subdev, mask, (void *)rtai_comedi_callback, task);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_command(void *dev, comedi_cmd *cmd)
{
int retval;
RTAI_COMEDI_LOCK(dev, cmd->subdev);
retval = comedi_command(dev, (void *)cmd);
RTAI_COMEDI_UNLOCK(dev, cmd->subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_command_test(void *dev, comedi_cmd *cmd)
{
int retval;
RTAI_COMEDI_LOCK(dev, cmd->subdev);
retval = comedi_command_test(dev, (void *)cmd);
RTAI_COMEDI_UNLOCK(dev, cmd->subdev);
return retval;
}
static RTAI_SYSCALL_MODE int RT_comedi_command(void *dev, struct cmds_ofstlens *ofstlens, long test)
{
int retval;
comedi_cmd cmd[2]; // 2 instances, a safe room for 64 getting into 32
memcpy(cmd, (void *)ofstlens + ofstlens->cmd_ofst, ofstlens->cmd_len);
cmd[0].chanlist = (void *)ofstlens + ofstlens->chanlist_ofst;
cmd[0].chanlist_len = ofstlens->chanlist_len;
cmd[0].data = (void *)ofstlens + ofstlens->data_ofst;
cmd[0].data_len = ofstlens->data_len;
retval = test ? _comedi_command_test(dev, cmd) : _comedi_command(dev, cmd);
return retval;
}
RTAI_SYSCALL_MODE long rt_comedi_command_data_read(void *dev, unsigned int subdev, long nchans, lsampl_t *data)
{
void *aibuf;
int i, ofsti, ofstf, size;
#if 1
if (comedi_map(dev, subdev, &aibuf)) {
return RTE_OBJINV;
}
if ((i = comedi_get_buffer_contents(dev, subdev)) < nchans) {
return i;
}
size = comedi_get_buffer_size(dev, subdev);
RTAI_COMEDI_LOCK(dev, subdev);
ofstf = ofsti = comedi_get_buffer_offset(dev, subdev);
for (i = 0; i < nchans; i++) {
data[i] = *(sampl_t *)(aibuf + ofstf % size);
ofstf += sizeof(sampl_t);
}
comedi_mark_buffer_read(dev, subdev, ofstf - ofsti);
RTAI_COMEDI_UNLOCK(dev, subdev);
#else
comedi_device *cdev = (comedi_device *)dev;
comedi_async *async;
RTAI_COMEDI_LOCK(dev, subdev);
if (subdev >= cdev->n_subdevices) {
return RTE_OBJINV;
}
if ((async = (cdev->subdevices + cdev->n_subdevices)->async) == NULL) {
return RTE_OBJINV;
}
aibuf = (sampl_t *)async->prealloc_buf;
if ((i = comedi_buf_read_n_available(async)) < nchans) {
return i;
}
ofstf = ofsti = async->buf_read_ptr;
size = async->prealloc_bufsz;
for (i = 0; i < nchans; i++) {
data[i] = *(sampl_t *)(aibuf + ofstf % size);
ofstf += sizeof(sampl_t);
}
comedi_buf_read_alloc(async, ofstf - ofsti);
comedi_buf_read_free(async, ofstf - ofsti);
RTAI_COMEDI_UNLOCK(dev, subdev);
#endif
return nchans;
}
#define WAIT 0
#define WAITIF 1
#define WAITUNTIL 2
static inline int __rt_comedi_command_data_wread(void *dev, unsigned int subdev, long nchans, lsampl_t *data, RTIME until, unsigned int *cbmaskarg, int waitmode)
{
unsigned int cbmask, mask;
long retval, kspace;
if ((kspace = KSPACE(cbmaskarg))) {
mask = cbmaskarg[0];
} else {
rt_get_user(mask, cbmaskarg);
}
switch (waitmode) {
case WAIT:
retval = rt_comedi_wait(&cbmask);
break;
case WAITIF:
retval = rt_comedi_wait_if(&cbmask);
break;
case WAITUNTIL:
retval = _rt_comedi_wait_until(&cbmask, until);
break;
default: // useless, just to avoid compiler warnings
return RTE_PERM;
}
if (!retval && (mask & cbmask)) {
if (kspace) {
cbmaskarg[0] = cbmask;
} else {
rt_put_user(cbmask, cbmaskarg);
}
return rt_comedi_command_data_read(dev, subdev, nchans, data);
}
return retval;
}
RTAI_SYSCALL_MODE long rt_comedi_command_data_wread(void *dev, unsigned int subdev, long nchans, lsampl_t *data, unsigned int *cbmask)
{
return __rt_comedi_command_data_wread(dev, subdev, nchans, data, (RTIME)0, cbmask, WAIT);
}
RTAI_SYSCALL_MODE long rt_comedi_command_data_wread_if(void *dev, unsigned int subdev, long nchans, lsampl_t *data, unsigned int *cbmask)
{
return __rt_comedi_command_data_wread(dev, subdev, nchans, data, (RTIME)0, cbmask, WAITIF);
}
RTAI_SYSCALL_MODE long _rt_comedi_command_data_wread_until(void *dev, unsigned int subdev, long nchans, lsampl_t *data, unsigned int *cbmask, RTIME until)
{
return __rt_comedi_command_data_wread(dev, subdev, nchans, data, until, cbmask, WAITUNTIL);
}
RTAI_SYSCALL_MODE long _rt_comedi_command_data_wread_timed(void *dev, unsigned int subdev, long nchans, lsampl_t *data, unsigned int *cbmask, RTIME delay)
{
return _rt_comedi_command_data_wread_until(dev, subdev, nchans, data, cbmask, rt_get_time() + delay);
}
RTAI_SYSCALL_MODE long RT_comedi_command_data_wread(void *dev, unsigned int subdev, long nchans, lsampl_t *data, unsigned int *cbmask, unsigned int datalen, RTIME time)
{
switch (nchans & 0x3) {
case 0:
return __rt_comedi_command_data_wread(dev, subdev, nchans >> 2, data, (RTIME)0, cbmask, WAIT);
case 1:
return __rt_comedi_command_data_wread(dev, subdev, nchans >> 2, data, (RTIME)0, cbmask, WAITIF);
case 2:
return __rt_comedi_command_data_wread(dev, subdev, nchans >> 2, data, time, cbmask, WAITUNTIL);
case 3:
return _rt_comedi_command_data_wread_until(dev, subdev, nchans >> 2, data, cbmask, rt_get_time() + time);
}
return 0;
}
static RTAI_SYSCALL_MODE int _comedi_data_write(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, lsampl_t data)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_data_write(dev, subdev, chan, range, aref, data);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_data_read(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, lsampl_t *data)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_data_read(dev, subdev, chan, range, aref, data);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_data_read_delayed(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, lsampl_t *data, unsigned int nanosec)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_data_read_delayed(dev, subdev, chan, range, aref, data, nanosec);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_data_read_hint(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_data_read_hint(dev, subdev, chan, range, aref);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_dio_config(void *dev, unsigned int subdev, unsigned int chan, unsigned int io)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_dio_config(dev, subdev, chan, io);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_dio_read(void *dev, unsigned int subdev, unsigned int chan, unsigned int *val)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_dio_read(dev, subdev, chan, val);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_dio_write(void *dev, unsigned int subdev, unsigned int chan, unsigned int val)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_dio_write(dev, subdev, chan, val);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_dio_bitfield(void *dev, unsigned int subdev, unsigned int write_mask, unsigned int *bits)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_dio_bitfield(dev, subdev, write_mask, bits);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_get_n_subdevices(void *dev)
{
return comedi_get_n_subdevices(dev);
}
static RTAI_SYSCALL_MODE int _comedi_get_version_code(void *dev)
{
return comedi_get_version_code(dev);
}
RTAI_SYSCALL_MODE char *rt_comedi_get_driver_name(void *dev, char *name)
{
const char *kname;
if ((kname = comedi_get_driver_name((void *)dev)) != 0) {
strncpy(name, kname, COMEDI_NAMELEN);
return name;
};
return NULL;
}
RTAI_SYSCALL_MODE char *rt_comedi_get_board_name(void *dev, char *name)
{
const char *kname;
if ((kname = comedi_get_board_name((void *)dev)) != 0) {
strncpy(name, kname, COMEDI_NAMELEN);
return name;
}
return NULL;
}
static RTAI_SYSCALL_MODE int _comedi_get_subdevice_type(void *dev, unsigned int subdev)
{
return comedi_get_subdevice_type(dev, subdev);
}
static RTAI_SYSCALL_MODE int _comedi_find_subdevice_by_type(void *dev, int type, unsigned int start_subdevice)
{
return comedi_find_subdevice_by_type(dev, type, start_subdevice);
}
static RTAI_SYSCALL_MODE int _comedi_get_n_channels(void *dev, unsigned int subdev)
{
return comedi_get_n_channels(dev, subdev);
}
static RTAI_SYSCALL_MODE lsampl_t _comedi_get_maxdata(void *dev, unsigned int subdev, unsigned int chan)
{
return comedi_get_maxdata(dev, subdev, chan);
}
static RTAI_SYSCALL_MODE int _comedi_get_n_ranges(void *dev, unsigned int subdev, unsigned int chan)
{
return comedi_get_n_ranges(dev, subdev, chan);
}
static RTAI_SYSCALL_MODE int _comedi_do_insn(void *dev, comedi_insn *insn)
{
int retval;
RTAI_COMEDI_LOCK(dev, insn->subdev);
retval = comedi_do_insn(dev, insn);
RTAI_COMEDI_UNLOCK(dev, insn->subdev);
return retval;
}
RTAI_SYSCALL_MODE int rt_comedi_do_insnlist(void *dev, comedi_insnlist *ilist)
{
int i;
for (i = 0; i < ilist->n_insns; i ++) {
if ((ilist->insns[i].n = comedi_do_insn(dev, &ilist->insns[i])) < 0) {
break;
}
}
return i;
}
RTAI_SYSCALL_MODE int RT_comedi_do_insnlist(void *dev, long n_insns, struct insns_ofstlens *ofstlens)
{
#define RT_INSN(offset) (*((unsigned int *)(insns + ofstlens->offset)))
#define RT_INSN_ADR(offset) ((void *)ofstlens + ofstlens->offset)
int i;
void *insns = RT_INSN_ADR(insns_ofst);
unsigned int *data_ofsts = RT_INSN_ADR(data_ofsts);
lsampl_t *data = RT_INSN_ADR(data_ofst);
comedi_insn insn[2]; // 2 instances, a safe room for 64 getting into 32
for (i = 0; i < n_insns; i ++) {
memcpy(insn, insns, ofstlens->insn_len);
insn[0].data = data + data_ofsts[i];
insn[0].subdev = RT_INSN(subdev_ofst);
insn[0].chanspec = RT_INSN(chanspec_ofst);
if ((RT_INSN(n_ofst) = comedi_do_insn(dev, insn)) < 0) {
break;
}
insns += ofstlens->insn_len;
}
return i;
}
static inline int _rt_comedi_trigger(void *dev, unsigned int subdev)
{
comedi_insn insn;
lsampl_t data = 0;
insn.insn = INSN_INTTRIG;
insn.subdev = subdev;
insn.n = 1;
insn.data = &data;
return _comedi_do_insn(dev, &insn);
}
RTAI_SYSCALL_MODE int rt_comedi_trigger(void *dev, unsigned int subdev)
{
return _rt_comedi_trigger(dev, subdev);
}
static RTAI_SYSCALL_MODE int _comedi_poll(void *dev, unsigned int subdev)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_poll(dev, subdev);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
/* DEPRECATED FUNCTION
static RTAI_SYSCALL_MODE int _comedi_get_rangetype(unsigned int minor, unsigned int subdevice, unsigned int chan)
{
return comedi_get_rangetype(minor, subdevice, chan);
}
*/
static RTAI_SYSCALL_MODE unsigned int _comedi_get_subdevice_flags(void *dev, unsigned int subdev)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_get_subdevice_flags(dev, subdev);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_get_krange(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, comedi_krange *krange)
{
return comedi_get_krange(dev, subdev, chan, range, krange);
}
static RTAI_SYSCALL_MODE int _comedi_get_buf_head_pos(void * dev, unsigned int subdev)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_get_buf_head_pos(dev, subdev);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_set_user_int_count(void *dev, unsigned int subdev, unsigned int buf_user_count)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_set_user_int_count(dev, subdev, buf_user_count);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_map(void *dev, unsigned int subdev, void *ptr)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_map(dev, subdev, ptr);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static RTAI_SYSCALL_MODE int _comedi_unmap(void *dev, unsigned int subdev)
{
int retval;
RTAI_COMEDI_LOCK(dev, subdev);
retval = comedi_unmap(dev, subdev);
RTAI_COMEDI_UNLOCK(dev, subdev);
return retval;
}
static inline int __rt_comedi_wait(RTIME until, unsigned int *cbmask, int waitmode)
{
if (cbmask) {
long retval;
RT_TASK *task = _rt_whoami();
switch (waitmode) {
case WAIT:
retval = rt_task_suspend(task);
break;
case WAITIF:
retval = rt_task_suspend_if(task);
break;
case WAITUNTIL:
retval = rt_task_suspend_until(task, until);
break;
default: // useless, just to avoid compiler warnings
return RTE_PERM;
}
if (KSPACE(cbmask)) {
cbmask[0] = (unsigned int)task->resumsg;
} else {
rt_put_user((unsigned int)task->resumsg, cbmask);
}
task->resumsg = 0;
return retval;
}
return RTE_PERM;
}
RTAI_SYSCALL_MODE long rt_comedi_wait(unsigned int *cbmask)
{
return __rt_comedi_wait((RTIME)0, cbmask, WAIT);
}
RTAI_SYSCALL_MODE long rt_comedi_wait_if(unsigned int *cbmask)
{
return __rt_comedi_wait((RTIME)0, cbmask, WAITIF);
}
RTAI_SYSCALL_MODE long _rt_comedi_wait_until(unsigned int *cbmask, RTIME until)
{
return __rt_comedi_wait(until, cbmask, WAITUNTIL);
}
RTAI_SYSCALL_MODE long _rt_comedi_wait_timed(unsigned int *cbmask, RTIME delay)
{
return _rt_comedi_wait_until(cbmask, rt_get_time() + delay);
}
RTAI_SYSCALL_MODE long rt_comedi_command_data_write(void *dev, unsigned int subdev, long nchans, lsampl_t *data)
{
void *aobuf;
int i, ofsti, ofstf, size, avbs;
if (comedi_map(dev, subdev, &aobuf)) {
return RTE_OBJINV;
}
size = comedi_get_buffer_size(dev, subdev);
avbs = comedi_get_buffer_contents(dev, subdev);
if ((size - avbs) < nchans) {
return (size - avbs);
}
RTAI_COMEDI_LOCK(dev, subdev);
ofstf = ofsti = (comedi_get_buffer_offset(dev, subdev) + avbs) % size;
for (i = 0; i < nchans; i++) {
*(sampl_t *)(aobuf + ofstf % size) = data[i];
ofstf += sizeof(sampl_t);
}
comedi_mark_buffer_written(dev, subdev, ofstf - ofsti);
#if 0
if (!avbs) {
int retval;
if ((retval = _rt_comedi_trigger(dev, subdev)) < 0) {
return retval;
}
}
#endif
RTAI_COMEDI_UNLOCK(dev, subdev);
return nchans;
}
static struct rt_fun_entry rtai_comedi_fun[] = {
[_KCOMEDI_OPEN] = { 0, _comedi_open }
,[_KCOMEDI_CLOSE] = { 0, _comedi_close }
,[_KCOMEDI_LOCK] = { 0, _comedi_lock }
,[_KCOMEDI_UNLOCK] = { 0, _comedi_unlock }
,[_KCOMEDI_CANCEL] = { 0, _comedi_cancel }
,[_KCOMEDI_REGISTER_CALLBACK] = { 0, rt_comedi_register_callback }
,[_KCOMEDI_COMMAND] = { 0, _comedi_command }
,[_KCOMEDI_COMMAND_TEST] = { 0, _comedi_command_test }
,[_KCOMEDI_TRIGGER ] = { 0, rt_comedi_trigger }
,[_KCOMEDI_DATA_WRITE] = { 0, _comedi_data_write}
,[_KCOMEDI_DATA_READ] = { 0, _comedi_data_read }
,[_KCOMEDI_DATA_READ_DELAYED] = { 0, _comedi_data_read_delayed }
,[_KCOMEDI_DATA_READ_HINT] = { 0, _comedi_data_read_hint }
,[_KCOMEDI_DIO_CONFIG] = { 0, _comedi_dio_config }
,[_KCOMEDI_DIO_READ] = { 0, _comedi_dio_read }
,[_KCOMEDI_DIO_WRITE] = { 0, _comedi_dio_write }
,[_KCOMEDI_DIO_BITFIELD] = { 0, _comedi_dio_bitfield }
,[_KCOMEDI_GET_N_SUBDEVICES] = { 0, _comedi_get_n_subdevices }
,[_KCOMEDI_GET_VERSION_CODE] = { 0, _comedi_get_version_code }
,[_KCOMEDI_GET_DRIVER_NAME] = { 0, rt_comedi_get_driver_name }
,[_KCOMEDI_GET_BOARD_NAME] = { 0, rt_comedi_get_board_name }
,[_KCOMEDI_GET_SUBDEVICE_TYPE] = { 0, _comedi_get_subdevice_type }
,[_KCOMEDI_FIND_SUBDEVICE_TYPE] = { 0, _comedi_find_subdevice_by_type }
,[_KCOMEDI_GET_N_CHANNELS] = { 0, _comedi_get_n_channels }
,[_KCOMEDI_GET_MAXDATA] = { 0, _comedi_get_maxdata }
,[_KCOMEDI_GET_N_RANGES] = { 0, _comedi_get_n_ranges }
,[_KCOMEDI_DO_INSN] = { 0, _comedi_do_insn }
,[_KCOMEDI_DO_INSN_LIST] = { 0, rt_comedi_do_insnlist }
,[_KCOMEDI_POLL] = { 0, _comedi_poll }
/*
,[_KCOMEDI_GET_RANGETYPE] = { 0, _comedi_get_rangetype }
*/
,[_KCOMEDI_GET_SUBDEVICE_FLAGS] = { 0, _comedi_get_subdevice_flags }
,[_KCOMEDI_GET_KRANGE] = { 0, _comedi_get_krange }
,[_KCOMEDI_GET_BUF_HEAD_POS] = { 0, _comedi_get_buf_head_pos }
,[_KCOMEDI_SET_USER_INT_COUNT] = { 0, _comedi_set_user_int_count }
,[_KCOMEDI_MAP] = { 0, _comedi_map }
,[_KCOMEDI_UNMAP] = { 0, _comedi_unmap }
,[_KCOMEDI_WAIT] = { 1, rt_comedi_wait }
,[_KCOMEDI_WAIT_IF] = { 0, rt_comedi_wait_if }
,[_KCOMEDI_WAIT_UNTIL] = { 1, _rt_comedi_wait_until }
,[_KCOMEDI_WAIT_TIMED] = { 1, _rt_comedi_wait_timed }
,[_KCOMEDI_COMD_DATA_READ] = { 0, rt_comedi_command_data_read }
,[_KCOMEDI_COMD_DATA_WREAD] = { 1, rt_comedi_command_data_wread }
,[_KCOMEDI_COMD_DATA_WREAD_IF] = { 0, rt_comedi_command_data_wread_if }
,[_KCOMEDI_COMD_DATA_WREAD_UNTIL] = { 1, _rt_comedi_command_data_wread_until }
,[_KCOMEDI_COMD_DATA_WREAD_TIMED] = { 1, _rt_comedi_command_data_wread_timed }
,[_KCOMEDI_COMD_DATA_WRITE] = { 0, rt_comedi_command_data_write }
,[_RT_KCOMEDI_COMMAND] = { 0, RT_comedi_command }
,[_RT_KCOMEDI_DO_INSN_LIST] = { 0, RT_comedi_do_insnlist }
,[_RT_KCOMEDI_COMD_DATA_WREAD] = { 0, RT_comedi_command_data_wread }
};
#ifdef CONFIG_RTAI_USE_LINUX_COMEDI
extern void *rt_comedi_request_irq;
extern void *rt_comedi_release_irq;
extern void *rt_comedi_busy_sleep;
#define RTAI_NR_IRQS IPIPE_NR_XIRQS
static int (*comedi_irq_handler_p[RTAI_NR_IRQS])(unsigned int, void *);
static int comedi_irq_handler(unsigned int irq, void *dev_id)
{
comedi_irq_handler_p[irq](irq, dev_id);
rt_enable_irq(irq);
return IRQ_HANDLED;
}
static int comedi_request_irq(unsigned int irq, int (*handler)(unsigned int irq, void *dev_id), unsigned long flags, const char *name, void *dev)
{
int retval;
if (comedi_irq_handler_p[irq]) {
return -EBUSY;
}
if ((retval = rt_request_irq(irq, comedi_irq_handler, dev, 0))) {
return retval;
}
comedi_irq_handler_p[irq] = handler;
rt_startup_irq(irq);
return 0;
}
static void comedi_release_irq(unsigned int irq, void *dev)
{
rt_shutdown_irq(irq);
rt_release_irq(irq);
}
static int us2tsc;
void comedi_busy_sleep(int us)
{
RTIME break_time;
break_time = rtai_rdtsc() + us*us2tsc;
while (rtai_rdtsc() < break_time);
}
#endif /* CONFIG_RTAI_USE_LINUX_COMEDI) */
int __rtai_comedi_init(void)
{
if( set_rt_fun_ext_index(rtai_comedi_fun, FUN_COMEDI_LXRT_INDX) ) {
printk("Recompile your module with a different index\n");
return -EACCES;
}
#ifdef CONFIG_RTAI_USE_LINUX_COMEDI
us2tsc = tuned.cpu_freq/1000000;
rt_comedi_request_irq = comedi_request_irq;
rt_comedi_release_irq = comedi_release_irq;
rt_comedi_busy_sleep = comedi_busy_sleep;
#endif
return 0;
}
void __rtai_comedi_exit(void)
{
#ifdef CONFIG_RTAI_USE_LINUX_COMEDI
int irq;
for (irq = 0; irq < RTAI_NR_IRQS; irq++) {
if (comedi_irq_handler_p[irq]) {
comedi_release_irq(irq, NULL);
}
}
rt_comedi_request_irq = rt_request_irq;
rt_comedi_release_irq = rt_release_irq;
rt_comedi_busy_sleep = __udelay;
#endif
reset_rt_fun_ext_index(rtai_comedi_fun, FUN_COMEDI_LXRT_INDX);
}
module_init(__rtai_comedi_init);
module_exit(__rtai_comedi_exit);
EXPORT_SYMBOL(rt_comedi_wait);
EXPORT_SYMBOL(rt_comedi_wait_if);
EXPORT_SYMBOL(_rt_comedi_wait_until);
EXPORT_SYMBOL(_rt_comedi_wait_timed);
EXPORT_SYMBOL(rt_comedi_get_driver_name);
EXPORT_SYMBOL(rt_comedi_get_board_name);
EXPORT_SYMBOL(rt_comedi_register_callback);
EXPORT_SYMBOL(rt_comedi_command_data_read);
EXPORT_SYMBOL(rt_comedi_command_data_wread);
EXPORT_SYMBOL(rt_comedi_command_data_wread_if);
EXPORT_SYMBOL(_rt_comedi_command_data_wread_until);
EXPORT_SYMBOL(_rt_comedi_command_data_wread_timed);
EXPORT_SYMBOL(rt_comedi_do_insnlist);
EXPORT_SYMBOL(rt_comedi_trigger);
EXPORT_SYMBOL(rt_comedi_command_data_write);

28
addons/comedi/kcomedi.c Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2002 Thomas Leibner (leibner@t-online.de) (first complete writeup)
* 2002 David Schleef (ds@schleef.org) (COMEDI master)
* 2002 Lorenzo Dozio (dozio@aero.polimi.it) (made it all work)
* 2002 Paolo Mantegazza (mantegazza@aero.polimi.it) (hints/support)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
/**
* This file is the non-inline KComedilib-LXRT userspace lib.
* It will be compiled into a libkcomedilxrt.a library with which
* your application can link if it included the rtai_comedi.h file.
*/
#include <rtai_comedi.h>

View file

@ -0,0 +1,117 @@
#
# Copyright (C) 2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
#
# 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, Inc., 675 Mass Ave, Cambridge MA 02139,
# USA; 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; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# WHAT TO DO:
# See "WHAT TO DO" in README in this directory.
# END OF WHAT TO DO.
#
# >>> Save original comedi dir
#
if test -d ../comedi.orig; then
echo "*** comedi.orig exists, no copy made ***"
else
cp -r ../comedi ../comedi.orig
fi
#
# >>> Set generic calls in comedi.
#
for i in `find . -name "*.c"`; do cat $i | sed s/request_irq/comedi_request_irq/g | sed s/free_irq/comedi_free_irq/g | sed s/udelay/comedi_udelay/g | sed s/spin_lock_irqsave/comedi_spin_lock_irqsave/g | sed s/spin_unlock_irqrestore/comedi_spin_unlock_irqrestore/g > newcopy; mv newcopy $i; done
#
# >>> Create comedi_system.h by cleaning this script part, care of not inserting
# >>> blank lines but the one that separates this script from comedi_system.h
# >>> body.
#
cat $0 | sed '1,/^$/ d' > comedi_system.h
#
# >>> Add an include for comedi_system.h in comedidev.h, to be seen everywhere.
#
cat comedidev.h | sed '/comedi.h/ i\#include "comedi_system.h"' > newcopy
mv newcopy comedidev.h
#
# >>> Append and export pointers for dynamically linking rtai_comedi extensions.
#
echo "" >>comedi_ksyms.c
echo "int (*rt_comedi_request_irq)(unsigned int, irq_handler_t, unsigned long, const char *, void *) = request_irq;" >>comedi_ksyms.c
echo "void (*rt_comedi_release_irq)(unsigned int, void *) = free_irq;" >>comedi_ksyms.c
echo "void (*rt_comedi_busy_sleep)(unsigned long) = __udelay;" >>comedi_ksyms.c
echo "" >>comedi_ksyms.c
echo "EXPORT_SYMBOL(rt_comedi_request_irq);" >>comedi_ksyms.c
echo "EXPORT_SYMBOL(rt_comedi_release_irq);" >>comedi_ksyms.c
echo "EXPORT_SYMBOL(rt_comedi_busy_sleep);" >>comedi_ksyms.c
#
# >>> Simulate a comedi.org distribution, to cheat RTAI configure for a while.
#
mkdir include
mkdir include/linux
cp comedi.h include/linux
cp comedilib.h include/linux
exit
#ifndef _COMEDI_SYSTEM_H_
#define _COMEDI_SYSTEM_H_
#ifdef CONFIG_IPIPE
#include <linux/version.h>
#include <linux/interrupt.h>
extern int (*rt_comedi_request_irq)(unsigned int, irq_handler_t, unsigned long, const char *, void *);
extern void (*rt_comedi_release_irq)(unsigned int, void *);
extern void (*rt_comedi_busy_sleep)(unsigned long);
#define comedi_request_irq(irq, handler, flags, name, dev) \
({ rt_comedi_request_irq(irq, (void *)handler, flags, name, dev); })
#define comedi_free_irq(irq, dev) \
rt_comedi_release_irq(irq, dev)
#define comedi_udelay(usec) \
rt_comedi_busy_sleep(usec)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
#define COMEDI_SPIN_LOCKP(lock_ptr) lock_ptr
#else
#define COMEDI_SPIN_LOCKP(lock_ptr) ((raw_spinlock_t *)lock_ptr)
#endif
#define comedi_spin_lock_irqsave(lock_ptr, flags) \
({ local_irq_save_hw(flags); _raw_spin_lock(COMEDI_SPIN_LOCKP(lock_ptr)); flags; })
#define comedi_spin_unlock_irqrestore(lock_ptr, flags) \
do { _raw_spin_unlock(COMEDI_SPIN_LOCKP(lock_ptr)); local_irq_restore_hw(flags); } while (0)
#else
#define comedi_request_irq(irq, handler, flags, device, dev_id) \
request_irq(irq, handler, flags, device, dev_id)
#define comedi_free_irq(irq, dev_id) \
free_irq(irq, dev_id)
#define comedi_udelay(usec) \
udelay(usec)
#define comedi_spin_lock_irqsave(lock_ptr, flags) \
({ spin_lock_irqsave(lock_ptr, flags); flags; })
#define comedi_spin_unlock_irqrestore(lock_ptr, flags) \
spin_unlock_irqrestore(lock_ptr, flags)
#endif
#endif /* _COMEDI_SYSTEM_H_ */

1036
addons/comedi/rtai_comedi.h Normal file

File diff suppressed because it is too large Load diff

227
addons/cpp/GNUmakefile.am Normal file
View file

@ -0,0 +1,227 @@
moduledir = @RTAI_MODULE_DIR@
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
include_HEADERS = rtai_cpp.h
noinst_HEADERS = \
bits.h \
cond.h \
count.h \
iostream.h \
linux_wrapper.h \
mbx.h \
module.h \
mutex.h \
new.h \
rtai_wrapper.h \
rtai_pqueue_wrapper.h \
rtai_pthread_int_wrapper.h \
rtai_pthread_wrapper.h \
tld_key.h \
rtf.h \
sem.h \
task.h \
tbx.h \
time.h \
trace.h \
watchdog.h
libcpp_a_SOURCES = \
builtin.c \
cs.cc \
cond.cc \
count.cc \
init.c \
iostream.cc \
mbx.cc \
module.cc \
mutex.cc \
sem.cc \
task.cc \
time.cc \
tld_key.c \
rtai_wrapper.c
if CONFIG_RTAI_TRACE
libcpp_a_SOURCES += trace.cc
endif
libcpp_bits_a_SOURCES = \
bits.cc \
bits_init.c \
linux_wrapper.c
libcpp_rtf_a_SOURCES = \
rtf.cc \
rtf_init.c \
linux_wrapper.c
libcpp_tbx_a_SOURCES = \
tbx.cc \
tbx_init.c \
linux_wrapper.c
libcpp_wd_a_SOURCES = \
watchdog_init.c \
watchdog.cc \
linux_wrapper.c
crt_files = \
crtbegin.c \
crtend.c \
crtmbegin.c \
crtmend.c \
crtsbegin.c \
crtsend.c
crtobjs = $(crt_files:%.c=%.o)
if CONFIG_KBUILD
modules = rtai_cpp.ko rtai_cpp_rtf.ko rtai_cpp_tbx.ko rtai_cpp_wd.ko
rtai_cpp.ko: @RTAI_KBUILD_ENV@
rtai_cpp.ko: $(libcpp_a_SOURCES) $(noinst_HEADERS)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
rtai_cpp_bits.ko: @RTAI_KBUILD_ENV@
rtai_cpp_bits.ko: $(libcpp_bits_a_SOURCES) $(noinst_HEADERS)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
rtai_cpp_rtf.ko: @RTAI_KBUILD_ENV@
rtai_cpp_rtf.ko: $(libcpp_rtf_a_SOURCES) $(noinst_HEADERS)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
rtai_cpp_tbx.ko: @RTAI_KBUILD_ENV@
rtai_cpp_tbx.ko: $(libcpp_tbx_a_SOURCES) $(noinst_HEADERS)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
rtai_cpp_wd.ko: @RTAI_KBUILD_ENV@
rtai_cpp_wd.ko: $(libcpp_wd_a_SOURCES) $(noinst_HEADERS)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
else
noinst_LIBRARIES = \
libcpp.a \
libcpp_bits.a \
libcpp_rtf.a \
libcpp_tbx.a \
libcpp_wd.a
modules = $(foreach lib,$(noinst_LIBRARIES),$(patsubst lib%.a,rtai_%.o,$(lib)))
libcpp_a_AR = $(CROSS_COMPILE)ar cru
libcpp_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_a_CXXFLAGS = \
@RTAI_KMOD_CXXFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_bits_a_AR = $(CROSS_COMPILE)ar cru
libcpp_bits_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_bits_a_CXXFLAGS = \
@RTAI_KMOD_CXXFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_rtf_a_AR = $(CROSS_COMPILE)ar cru
libcpp_rtf_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_rtf_a_CXXFLAGS = \
@RTAI_KMOD_CXXFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_tbx_a_AR = $(CROSS_COMPILE)ar cru
libcpp_tbx_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_tbx_a_CXXFLAGS = \
@RTAI_KMOD_CXXFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_wd_a_AR = $(CROSS_COMPILE)ar cru
libcpp_wd_a_CFLAGS = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
libcpp_wd_a_CXXFLAGS = \
@RTAI_KMOD_CXXFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
CRTFLAGS = \
-I../.. \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../base/include
crtsbegin.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_BEGIN -DNO_MOD_INIT -c $< -o $@
crtsend.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_END -DNO_MOD_INIT -c $< -o $@
crtbegin.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_BEGIN -c $< -o $@
crtend.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_END -c $< -o $@
crtmbegin.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_BEGIN -DUSE_MAIN -c $< -o $@
crtmend.o : $(srcdir)/crt.c
$(CC) $(CRTFLAGS) -DCRT_END -DUSE_MAIN -c $< -o $@
rtai_%.o: lib%.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: $(modules) $(crtobjs)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: $(modules) $(crtobjs)
$(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $(modules) $(DESTDIR)$(moduledir)
$(mkinstalldirs) $(DESTDIR)$(libdir)
$(INSTALL_DATA) $(crtobjs) $(DESTDIR)$(libdir)
EXTRA_DIST = crt.c

92
addons/cpp/bits.cc Normal file
View file

@ -0,0 +1,92 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: bits.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "bits.h"
#include "rtai.h"
namespace RTAI {
Bits::Bits(){
rt_printk("Bits::Bits( ) %p\n",this);
m_Bits = 0;
}
Bits::Bits( unsigned long mask )
{
rt_printk("Bits::Bits( unsigned long mask=%lu) %p\n",mask,this);
m_Bits = 0;
init( mask );
}
Bits::~Bits()
{
if( m_Bits != 0 )
rt_bits_delete( m_Bits );
}
void Bits::init(unsigned long mask)
{
rt_bits_init(m_Bits, mask );
}
unsigned long Bits::get_bits(){
return rt_get_bits( m_Bits );
}
int Bits::reset( unsigned long mask )
{
return rt_bits_reset( m_Bits, mask );
}
unsigned long Bits::signal( Function setfun, unsigned long masks )
{
return rt_bits_signal( m_Bits, setfun, masks );
}
int Bits::wait(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks,
unsigned long *resulting_mask )
{
return rt_bits_wait( m_Bits, testfun, testmasks, exitfun, exitmasks, resulting_mask );
}
int Bits::wait_if(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks,
unsigned long *resulting_mask )
{
return rt_bits_wait_if( m_Bits, testfun, testmasks, exitfun, exitmasks, resulting_mask );
}
int Bits::wait_until(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks, const Count& time,
unsigned long *resulting_mask )
{
return rt_bits_wait_until( m_Bits, testfun, testmasks, exitfun, exitmasks, time, resulting_mask );
}
int Bits::wait_timed(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks, const Count& delay,
unsigned long *resulting_mask )
{
return rt_bits_wait_timed( m_Bits, testfun, testmasks, exitfun, exitmasks, delay , resulting_mask );
}
};

154
addons/cpp/bits.h Normal file
View file

@ -0,0 +1,154 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: bits.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __BITS_H__
#define __BITS_H__
#include "count.h"
#include "rtai_bits.h"
namespace RTAI {
/**
* Bits a wrapper class around the RTAI BITS
*/
class Bits
{
public:
/**
* Function types used by Bits
*/
enum Function {
all_set = ALL_SET, ///< all set
any_set = ANY_SET, ///< any set
all_clr = ALL_CLR, ///< all clear
any_clr = ANY_CLR, ///< any clear
all_set_and_any_set = ALL_SET_AND_ANY_SET, ///< all set and any clear
all_set_and_all_clr = ALL_SET_AND_ALL_CLR, ///< all set and all clear
all_set_and_any_clr = ALL_SET_AND_ANY_CLR, ///< all set and any clear
any_set_and_all_clr = ANY_SET_AND_ALL_CLR, ///< any set and all clear
any_set_and_any_clr = ANY_SET_AND_ANY_CLR, ///< any set and any clear
all_clr_and_any_clr = ALL_CLR_AND_ANY_CLR, ///< all clear and any clear
all_set_or_any_set = ALL_SET_OR_ANY_SET, ///< all set or any clear
all_set_or_all_clr = ALL_SET_OR_ALL_CLR, ///< all set or all clear
all_set_or_any_clr = ALL_SET_OR_ANY_CLR, ///< all set or any clear
any_set_or_all_clr = ANY_SET_OR_ALL_CLR, ///< all set or all clear
any_set_or_any_clr = ANY_SET_OR_ANY_CLR, ///< any set or any clear
all_clr_or_any_clr = ALL_CLR_OR_ANY_CLR, ///< all clear or any clear
};
public:
/**
* Default Constructor.
* when using the default constructor one has to call
* the init methode by hand before the object can be used.
*/
Bits();
/**
*Contructor
*@param mask The masked
* This constructor will automaticly call init
*/
Bits( unsigned long mask );
/**
* Destructor
*/
virtual ~Bits();
/**
* init will initialize the under laying BITS
* @param mask The mask
*/
void init(unsigned long mask);
/**
* Get the current status of the bits
* @return The 32 bits
*/
unsigned long get_bits();
/**
* Reset the bits
* @param mask the mask
* @return ?
*/
int reset( unsigned long mask );
/**
* Signal the bits
* @param setfun The set function
* @param masks the mask
* @return ?
*/
unsigned long signal( Function setfun, unsigned long masks );
/**
* Wait for a change
* @param testfun ?
* @param testmasks ?
* @param exitfun ?
* @param exitmask ?
* @return ?
*/
int wait(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks,
unsigned long *resulting_mask );
/**
* Wait for a change
* @param testfun ?
* @param testmasks ?
* @param exitfun ?
* @param exitmasks
* @return ?
*/
int wait_if(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks,
unsigned long *resulting_mask );
/**
* Wait for a change
* @param testfun ?
* @param testmasks ?
* @param exitfun ?
* @param exitmasks
* @return ?
*/
int wait_until(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks, const Count& time,
unsigned long *resulting_mask );
/**
* Wait for a change
* @param testfun ?
* @param testmasks ?
* @param exitfun ?
* @param exitmasks
* @return ?
*/
int wait_timed(Function testfun, unsigned long testmasks,
Function exitfun, unsigned long exitmasks, const Count& delay,
unsigned long *resulting_mask);
protected:
BITS* m_Bits;
private:
Bits(const Bits&);
Bits& operator=(const Bits&);
};
}; // namespace RTAI
#endif

77
addons/cpp/bits_init.c Normal file
View file

@ -0,0 +1,77 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: bits_init.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <rtai_sched.h>
#include <rtai_bits.h>
#include <rtai_malloc.h>
// RTAI-- MODULE INIT and CLEANUP functions
MODULE_LICENSE("GPL");
MODULE_AUTHOR("the RTAI-Team (contact person Erwin Rol)");
MODULE_DESCRIPTION("RTAI C++ BITS support");
BITS* __rt_bits_init(unsigned long mask){
BITS * bits;
bits = rt_malloc(sizeof(BITS));
if(bits == 0)
return 0;
memset(bits,0,sizeof(BITS));
rt_bits_init(bits,mask);
return bits;
}
int __rt_bits_delete(BITS *bits){
int result;
if(bits == 0)
return -1;
result = rt_bits_delete(bits);
rt_free(bits);
return result;
}
int __init rtai_cpp_bits_init(void){
return 0;
}
void rtai_cpp_bits_cleanup(void)
{
}
module_init(rtai_cpp_bits_init)
module_exit(rtai_cpp_bits_cleanup)

162
addons/cpp/builtin.c Normal file
View file

@ -0,0 +1,162 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: builtin.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <rtai_sched.h>
#include <rtai_malloc.h>
#if __GNUC__ < 3
void
__builtin_delete(void* vp){
rt_printk("__builtin_delete %p\n",vp);
if(vp != 0)
rt_free(vp);
}
void*
__builtin_new(int size){
void* vp = rt_malloc(size);
rt_printk("__builtin_new %p %d\n",vp,size);
return vp;
}
void
__builtin_vec_delete(void* vp){
rt_printk("__builtin_vec_delete %p\n",vp);
if(vp != 0)
rt_free(vp);
}
void*
__builtin_vec_new(int size){
void* vp = rt_malloc(size);
rt_printk("__builtin_vec_new %p %d\n",vp,size);
return vp;
}
#endif
extern void __default_terminate (void) __attribute__ ((__noreturn__));
void
__default_terminate(void)
{
while(1)
rt_task_suspend(rt_whoami());
}
void (*__terminate_func)(void) = __default_terminate;
void
__terminate(void)
{
(*__terminate_func)();
}
void
__pure_virtual(void)
{
rt_printk("pure virtual method called\n");
__terminate ();
}
/* Declare a pointer to void function type. */
typedef void (*func_ptr) (void);
static func_ptr* atexit_function_tab;
static int atexit_function_tab_size;
static int atexit_function_tab_len;
int atexit( func_ptr function )
{
rt_printk("atexit %p\n",function);
// we check if the pointer is NULL, this
// can happen when a second C++ modules is loaded
// and than unloaded. At unload time the second module
// will call the atexit handlers and delete
// the function table
if( atexit_function_tab == 0 ){
rt_printk("atexit_function_tab == NULL\n");
return -1;
}
if( atexit_function_tab_len >= atexit_function_tab_size)
return -1;
if( function == 0 )
return -1;
atexit_function_tab[ atexit_function_tab_len++ ] = function;
return 0;
}
void __do_atexit( void )
{
func_ptr *p = atexit_function_tab;
rt_printk("__do_atexit START\n");
// we check if the pointer is NULL, this
// can happen when a second C++ modules is loaded
// and than unloaded. At unload time the second module
// will call the atexit handlers and delete
// the function table
if( atexit_function_tab == 0 ){
rt_printk("atexit_function_tab == NULL\n");
return;
}
while(*p)
{
rt_printk("calling atexit function %p\n",p );
(*(p))();
p++;
if( atexit_function_tab_len-- )
break;
}
vfree( atexit_function_tab );
atexit_function_tab_size = 0;
atexit_function_tab_len = 0;
atexit_function_tab = 0;
rt_printk("__do_atexit END\n");
}
void __init_atexit( int max_size )
{
// we check if the pointer is NULL, this
// can happen when a second C++ modules is loaded
// and than unloaded. At unload time the second module
// will call the atexit handlers and delete
// the function table
if( atexit_function_tab != 0 ){
rt_printk("__init_atexit atexit_function_tab != NULL\n");
return;
}
atexit_function_tab_size = max_size;
atexit_function_tab_len = 0;
atexit_function_tab = vmalloc( sizeof(func_ptr) * atexit_function_tab_size);
memset( atexit_function_tab , 0 , sizeof(func_ptr) * atexit_function_tab_size );
}

51
addons/cpp/cond.cc Normal file
View file

@ -0,0 +1,51 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: cond.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cond.h"
#include "mutex.h"
namespace RTAI {
Condition::Condition()
: Semaphore(0, BIN_SEM)
{
}
Condition::~Condition(){
}
int Condition::wait( Mutex& mtx )
{
return rt_cond_wait( m_Sem, mtx.m_Sem );
}
int Condition::wait_until( Mutex& mtx,const Count& time)
{
return rt_cond_wait_until( m_Sem, mtx.m_Sem, time );
}
int Condition::wait_timed( Mutex& mtx, const Count& delay)
{
return rt_cond_wait_timed( m_Sem, mtx.m_Sem, delay );
}
}; // namespace RTAI

52
addons/cpp/cond.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: cond.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "rtai.h"
#include "count.h"
#include "sem.h"
#include "mutex.h"
#ifndef __COND_H__
#define __COND_H__
namespace RTAI {
/**
* Condition Variable
*/
class Condition
: public Semaphore
{
public:
Condition();
~Condition();
int wait( Mutex& mtx );
int wait_until( Mutex& mtx, const Count& time);
int wait_timed( Mutex& mtx, const Count& delay);
private:
Condition(const Condition&);
Condition& operator=(const Condition&);
};
}; // namespace RTAI
#endif

140
addons/cpp/count.cc Normal file
View file

@ -0,0 +1,140 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: count.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "count.h"
#include "rtai_sched.h"
namespace RTAI {
Count::Count(){
m_Count = 0;
}
Count::Count(const Count& count)
: m_Count(count.m_Count)
{
}
Count::Count(long long count)
: m_Count(count)
{
}
Count& Count::operator=(const Count& count)
{
m_Count = count.m_Count;
return *this;
}
Count& Count::operator=(long long count)
{
m_Count = count;
return *this;
}
Count Count::now(){
return Count( rt_get_time() );
}
Count Count::end(){
return Count(0x7FFFFFFFFFFFFFFFLL);
}
long long Count::to_time() const {
return count2nano( m_Count );
}
Count Count::from_time(long long time) {
Count tmp( nano2count(time) );
return tmp;
}
bool Count::operator==(const Count& count) const
{
return m_Count == count.m_Count;
}
bool Count::operator==(long long count) const
{
return m_Count == count;
}
bool Count::operator<(const Count& count)const{
return m_Count < count.m_Count;
}
bool Count::operator>(const Count& count)const {
return m_Count > count.m_Count;
}
bool Count::operator<=(const Count& count)const{
return m_Count <= count.m_Count;
}
bool Count::operator>=(const Count& count)const {
return m_Count >= count.m_Count;
}
Count& Count::operator+=(const Count& count){
m_Count += count.m_Count;
return *this;
}
Count& Count::operator+=(long long count) {
m_Count += count;
return *this;
}
Count& Count::operator-=(const Count& count) {
m_Count -= count.m_Count;
return *this;
}
Count& Count::operator-=(long long count){
m_Count -= count;
return *this;
}
Count Count::operator+(const Count& count) const {
Count tmp(m_Count + count.m_Count);
return tmp;
}
Count Count::operator+(long long count) const {
Count tmp(m_Count + count);
return tmp;
}
Count Count::operator-(const Count& count) const {
Count tmp(m_Count - count.m_Count);
return tmp;
}
Count Count::operator-(long long count) const {
Count tmp(m_Count - count);
return tmp;
}
}; // namespace RTAI

114
addons/cpp/count.h Normal file
View file

@ -0,0 +1,114 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: count.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __COUNT_H__
#define __COUNT_H__
namespace RTAI {
/**
* Tick Count helper class
*
* Ticks are sometimes needed by the system calls.
* For human readable time keeping, use the Time class.
*/
class Count {
public:
/**
* The count ticks
*/
typedef long long ticks;
/**
* The time in nanoseconds
*/
typedef long long nsecs;
/**
* Instantiates a Count object with count zero
*/
Count();
/**
* Make a deep copy of a Count instance
*/
Count(const Count& count);
/**
* Instantiates a Count object with counts on <count>
*
* @oaram count The system counts to be used
*/
explicit Count(ticks count);
Count& operator=(const Count& count);
Count& operator=(ticks count);
static Count now();
static Count end();
inline operator ticks() const { return m_Count; }
/**
* Returns the time in nanoseconds that this Count
* instance represents.
*/
nsecs to_time() const;
/**
* Factory Method. Creates a Count instance
* denoting <time> in nanoseconds
*
* @param time The time in nanoseconds
*/
static Count from_time(nsecs time);
bool operator==(const Count& count) const;
bool operator==(ticks count) const;
inline bool operator!=(const Count& count) const { return !this->operator==(count); }
inline bool operator!=(ticks count) const { return !this->operator==(count); }
bool operator<(const Count& count)const;
bool operator>(const Count& count)const;
bool operator<=(const Count& count)const;
bool operator>=(const Count& count)const;
Count& operator+=(const Count& count);
Count& operator+=(ticks count);
Count& operator-=(const Count& count);
Count& operator-=(ticks count);
Count operator+(const Count& count) const;
Count operator+(ticks count) const;
Count operator-(const Count& count) const;
Count operator-(ticks count) const;
protected:
ticks m_Count; // internal count ticks
};
}; // namespace RTAI
#endif

237
addons/cpp/crt.c Normal file
View file

@ -0,0 +1,237 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: crt.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Specialized bits of code needed to support construction and
* destruction of file-scope objects in C++ code.
*
* This code was partly taken from the GCC sources.
*
* Copyright:
*
* Copyright (C) 1991, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
* Contributed by Ron Guilmette (rfg@monkeys.com).
* Copyright (C) 2002 Erwin Rol (erwin@muffin.org).
*
* Licence:
*
* This library 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 library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* As a special exception, if you link this library with files
* compiled with GCC to produce an executable, this does not cause
* the resulting executable to be covered by the GNU General Public License.
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
*/
static int errno;
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <linux/vmalloc.h>
#include <rtai_malloc.h>
extern int rt_printk(const char *format, ...);
extern void __do_atexit( void );
extern int __init_atexit( int max_size );
#if (__GNUC__ <= 2)
#ifndef CTORS_SECTION_ASM_OP
#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\""
#endif
#ifndef DTORS_SECTION_ASM_OP
#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
#endif
#else /* ! (__GNUC__ > 3) */
extern void __do_global_ctors_aux(void);
#define __do_global_ctors __do_global_ctors_aux
extern void __do_global_dtors_aux(void);
#define __do_global_dtors __do_global_dtors_aux
#endif /* __GNUC__ > 3 */
/* Declare a pointer to void function type. */
#if (__GNUC__ <= 2)
typedef void (*func_ptr) (void);
#endif /* ! (__GNUC__ > 3) */
#ifdef CRT_BEGIN
#if (__GNUC__ <= 2)
extern int atexit( func_ptr function );
static func_ptr __DTOR_LIST__[];
static void
__do_global_dtors(void)
{
static func_ptr *p = __DTOR_LIST__ + 1;
static int completed = 0;
rt_printk("GLOBAL DTORS START\n");
while (*p)
{
p++;
(*(p-1)) ();
}
rt_printk("GLOBAL DTORS END\n");
completed = 1;
}
extern func_ptr __CTOR_LIST__[];
static void
__do_global_ctors(void)
{
unsigned long nptrs = (unsigned long) __CTOR_LIST__[0];
unsigned i;
rt_printk("GLOBAL CTORS START\n");
if (nptrs == (unsigned long)-1)
for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++);
for (i = nptrs; i >= 1; i--)
__CTOR_LIST__[i] ();
rt_printk("GLOBAL CTORS END\n");
}
#endif /* ! (__GNUC__ > 3) */
#ifdef USE_MAIN
extern int main(int argc, char* argv[]);
static int main_thread(void *unused){
sigset_t tmpsig;
int res = -1;
/* Block all signals except SIGKILL and SIGSTOP */
spin_lock_irq(&current->sigmask_lock);
tmpsig = current->blocked;
siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
__do_global_ctors();
res = main(0,0);
__do_global_dtors();
__do_atexit();
return res;
}
#endif // USE_MAIN
// RTAI-- MODULE INIT and CLEANUP functions
#ifdef NO_MOD_INIT
void init_cpp( void )
{
__init_atexit( 128 );
__do_global_ctors();
}
void cleanup_cpp( void )
{
__do_global_dtors();
__do_atexit();
}
#else /* NO_MOD_INIT */
#include <linux/kthread.h>
int __init startup_init(void)
{
__init_atexit( 128 );
#ifdef USE_MAIN
kthread_run(main_thread, NULL, "RTAI_KCPP_SUPRT");
#else
__do_global_ctors();
#endif
return 0;
}
void startup_cleanup(void)
{
#ifdef USE_MAIN
int waitpid_result = 1;
while( waitpid_result > 0 )
waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
#else
__do_global_dtors();
__do_atexit();
#endif
}
module_init(startup_init)
module_exit(startup_cleanup)
#endif /* NO_MOD_INIT */
#if (__GNUC__ <= 2)
/* Force cc1 to switch to .data section. */
static func_ptr force_to_data[0] __attribute__ ((__unused__)) = { };
asm (CTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
static func_ptr __CTOR_LIST__[1] __attribute__ ((__unused__))
= { (func_ptr) (-1) };
asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
static func_ptr __DTOR_LIST__[1] __attribute__ ((__unused__))
= { (func_ptr) (-1) };
#endif /* ! (__GNUC__ > 3) */
#else // CRT_BEGIN
#if (__GNUC__ <= 2)
/* Force cc1 to switch to .data section. */
static func_ptr force_to_data[0] __attribute__ ((__unused__)) = { };
asm (CTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
static func_ptr __CTOR_END__[1] __attribute__ ((__unused__))
= { (func_ptr) 0 };
asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
static func_ptr __DTOR_END__[1] __attribute__ ((__unused__))
= { (func_ptr) 0 };
#endif /* ! (__GNUC__ > 3) */
#endif // CRT_BEGIN

49
addons/cpp/cs.cc Normal file
View file

@ -0,0 +1,49 @@
#include "rtai_wrapper.h"
extern "C"
{
#include "rtai.h"
#include "rtai_malloc.h"
}
#if __GNUC__ < 3
/* use __builtin_delete() */
#else
void operator delete(void* vp)
{
rt_printk("my __builtin_delete %p\n",vp);
if(vp != 0)
rt_free(vp);
}
/* for gcc-3.3 */
void operator delete[](void* vp){
if(vp != 0)
rt_free(vp);
}
void *operator new(size_t size){
void* vp = rt_malloc(size);
return vp;
}
void *operator new[](size_t size){
void* vp = rt_malloc(size);
return vp;
}
/* __cxa_pure_virtual(void) support */
extern "C" void __cxa_pure_virtual(void)
{
rt_printk("attempt to use a virtual function before object has been constructed\n");
for ( ; ; );
}
#endif

65
addons/cpp/init.c Normal file
View file

@ -0,0 +1,65 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: init.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <rtai_malloc.h>
#include "tld_key.h"
extern void init_iostream( void );
// RTAI-- MODULE INIT and CLEANUP functions
MODULE_LICENSE("GPL");
MODULE_AUTHOR("the RTAI-Team (contact person Erwin Rol)");
MODULE_DESCRIPTION("RTAI C++ support");
int __init rtai_cpp_init(void){
cpp_key = __rt_tld_create_key();
if(cpp_key == -1){
rt_printk("Could not get free TLD key\n");
return -1;
}
rt_printk("Got %d TLD key\n",cpp_key);
init_iostream();
return 0;
}
void rtai_cpp_cleanup(void)
{
if(cpp_key != -1)
__rt_tld_free_key(cpp_key);
}
module_init(rtai_cpp_init)
module_exit(rtai_cpp_cleanup)

227
addons/cpp/iostream.cc Normal file
View file

@ -0,0 +1,227 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: iostream.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "rtai.h"
#include "iostream.h"
#include <new.h>
namespace std {
ostream cerr;
ostream cout;
ostream& endl( ostream& s )
{
return s.put( '\n' );
}
ostream& output_on( ostream& s )
{
return s.set_output_on( true );
}
ostream& output_off( ostream& s )
{
return s.set_output_on( false );
}
ostream::ostream()
: m_OutputOn( true )
{
rt_printk("ostream::ostream() %p\n",(void*)this);
}
ostream::~ostream()
{
rt_printk("ostream::~ostream() %p\n",(void*)this);
}
ostream& ostream::set_output_on( bool f )
{
m_OutputOn = f;
return *this;
}
ostream& ostream::put(char c)
{
if( m_OutputOn )
rt_printk( "%c" , c );
return *this;
}
ostream& ostream::write(const char *s)
{
if( m_OutputOn )
rt_printk("%s",s);
return *this;
}
ostream& ostream::write(const char *s, int n)
{
if ( m_OutputOn )
{
for (int i = 0; i < n; i++) {
put(*s++);
}
}
return *this;
}
ostream& ostream::operator<<( const char* s )
{
return write(s);;
}
ostream& ostream::operator<<( const void* p )
{
if( m_OutputOn )
rt_printk("%p",p);
return *this;
}
ostream& ostream::operator<<( unsigned char c)
{
if( m_OutputOn )
rt_printk("%c",c);
return *this;
}
ostream& ostream::operator<<( unsigned short n)
{
if( m_OutputOn )
rt_printk("%d",n);
return *this;
}
ostream& ostream::operator<<( unsigned int n)
{
if( m_OutputOn )
rt_printk("%d",n);
return *this;
}
ostream& ostream::operator<<( unsigned long n )
{
if( m_OutputOn )
rt_printk("%lu",n);
return *this;
}
ostream& ostream::operator<<( unsigned long long n)
{
if( m_OutputOn )
rt_printk("<unsigned long long not implemented>");
return *this;
}
ostream& ostream::operator<<( signed char c)
{
if( m_OutputOn )
rt_printk("%c",c);
return *this;
}
ostream& ostream::operator<<( signed short n)
{
if( m_OutputOn )
rt_printk("%d",n);
return *this;
}
ostream& ostream::operator<<( signed int n)
{
if( m_OutputOn )
rt_printk("%d",n);
return *this;
}
ostream& ostream::operator<<( signed long n )
{
if( m_OutputOn )
rt_printk("%ld",n);
return *this;
}
ostream& ostream::operator<<( signed long long n)
{
if( m_OutputOn )
rt_printk("<long long not implemented>");
return *this;
}
ostream& ostream::operator<<( float f )
{
if( m_OutputOn )
rt_printk("<float not implemented>");
return *this;
}
ostream& ostream::operator<<( double f )
{
if( m_OutputOn )
rt_printk("<double not implemented>");
return *this;
}
ostream& ostream::operator<<( long double f)
{
if( m_OutputOn )
rt_printk("<long double not implemented>");
return *this;
}
}; // namespace std
// doing a placement new with the address of the two global
// objects. This is a dirty hack to have just these two
// constructors called, because at the moment the rtai_cpp
// modules only support one module doing global constructors/destructors
// and atexit handling
extern "C" {
void init_iostream()
{
new( (void*)&std::cerr ) std::ostream;
new( (void*)&std::cout ) std::ostream;
}
} // end extern "C"

94
addons/cpp/iostream.h Normal file
View file

@ -0,0 +1,94 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: iostream.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __IOSTREAM_H__
#define __IOSTREAM_H__
namespace std {
class ostream;
typedef ostream& (*__omanip)(ostream&);
/**
* printk Helper Class
*/
class ostream {
public:
ostream();
virtual ~ostream();
ostream& set_output_on( bool f );
ostream& put(char c);
ostream& put(unsigned char c) { return put((char)c); }
ostream& put(signed char c) { return put((char)c); }
ostream& write(const char *s);
ostream& write(const unsigned char *s) {
return write((const char*)s);
}
ostream& write(const signed char *s) {
return write((const char*)s);
}
ostream& write(const char *s, int n);
ostream& write(const unsigned char *s, int n) {
return write((const char*)s,n);
}
ostream& write(const signed char *s, int n) {
return write((const char*)s,n);
}
ostream& operator<<( const char* s );
ostream& operator<<( const void* p );
ostream& operator<<( unsigned char n);
ostream& operator<<( unsigned short n);
ostream& operator<<( unsigned int n);
ostream& operator<<( unsigned long n );
ostream& operator<<( unsigned long long n);
ostream& operator<<( signed char n);
ostream& operator<<( signed short n);
ostream& operator<<( signed int n );
ostream& operator<<( signed long n );
ostream& operator<<( signed long long n);
ostream& operator<<( float f );
ostream& operator<<( double f );
ostream& operator<<( long double f);
ostream& operator<<(__omanip func) { return (*func)(*this); }
protected:
bool m_OutputOn;
};
extern ostream& endl( ostream& s );
extern ostream& output_off( ostream& s);
extern ostream& output_on( ostream& s);
extern ostream cerr;
extern ostream cout;
}; // namespace std
#endif

View file

@ -0,0 +1,32 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: linux_wrapper.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <asm/system.h>
#include <linux/smp.h>
#include "linux_wrapper.h"
int __smp_num_cpus(){
return smp_num_cpus;
}

View file

@ -0,0 +1,38 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: linux_wrapper.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __LINUX_WRAPPER_H__
#define __LINUX_WRAPPER_H__
#ifdef __cplusplus
extern "C" {
#endif
extern int __smp_num_cpus(void);
#ifdef __cplusplus
}
#endif
#endif

164
addons/cpp/mbx.cc Normal file
View file

@ -0,0 +1,164 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: mbx.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "mbx.h"
#include "rtai_registry.h"
namespace RTAI {
Mailbox::Mailbox(){
rt_printk("Mailbox::Mailbox() %p\n",this);
m_Mailbox = 0;
m_Owner = true;
m_Named = false;
}
Mailbox::Mailbox(int size){
rt_printk("Mailbox::Mailbox(int size=%d) %p\n",size,this);
m_Mailbox = 0;
m_Owner = true;
m_Named = false;
init(size);
}
Mailbox::Mailbox(const char* name){
rt_printk("Mailbox::Mailbox(const char* name=%s) %p\n",name,this);
m_Mailbox = 0;
m_Owner = false;
m_Named = true;
init(name);
}
Mailbox::Mailbox(const char* name, int size){
rt_printk("Mailbox::Mailbox(const char* name=%s, int size=%d)%p\n",name ,size,this);
m_Mailbox = 0;
m_Owner = true;
m_Named = true;
init(name,size);
}
Mailbox::~Mailbox(){
rt_printk("Mailbox::~Mailbox() %p\n",this);
if(m_Mailbox != 0){
if( m_Owner ){
if( m_Named){
rt_named_mbx_delete(m_Mailbox);
} else {
rt_mbx_delete(m_Mailbox);
}
}
}
}
bool Mailbox::init(int size){
rt_printk("Mailbox::init(int size=%d) %p\n",size,this);
if(m_Mailbox == 0){
m_Named = false;
m_Owner = true;
rt_mbx_init(m_Mailbox, size);
if( m_Mailbox == 0)
return false;
else
return true;
} else {
return false;
}
}
bool Mailbox::init(const char* name, int size){
rt_printk("Mailbox::init(int size=%d) %p\n",size,this);
if(m_Mailbox == 0){
m_Owner = true;
m_Named = true;
m_Mailbox = rt_named_mbx_init(name, size);
if( m_Mailbox == 0)
return false;
else
return true;
} else {
return false;
}
}
bool Mailbox::init(const char* name)
{
rt_printk("Mailbox::init() %p\n",this);
if(m_Mailbox == 0){
m_Owner = false;
m_Named = true;
unsigned long num = nam2num(name);
if( rt_get_type( num ) == IS_MBX ){
m_Mailbox = static_cast<MBX*>(rt_get_adr( num ));
return true;
} else {
return false;
}
} else {
return false;
}
}
int Mailbox::send(const void* msg, int msg_size){
return rt_mbx_send(m_Mailbox,const_cast<void*>(msg),msg_size);
}
int Mailbox::send_wp(const void* msg, int msg_size){
return rt_mbx_send_wp(m_Mailbox,const_cast<void*>(msg),msg_size);
}
int Mailbox::send_if(const void* msg, int msg_size){
return rt_mbx_send_if(m_Mailbox,const_cast<void*>(msg),msg_size);
}
int Mailbox::send_until(const void* msg, int msg_size, const Count& time){
return rt_mbx_send_until(m_Mailbox,const_cast<void*>(msg),msg_size,time);
}
int Mailbox::send_timed(const void* msg, int msg_size, const Count& delay){
return rt_mbx_send_timed(m_Mailbox,const_cast<void*>(msg),msg_size,delay);
}
int Mailbox::receive(void* msg, int msg_size){
return rt_mbx_receive(m_Mailbox,msg,msg_size);
}
int Mailbox::receive_wp(void* msg, int msg_size){
return rt_mbx_receive_wp(m_Mailbox,msg,msg_size);
}
int Mailbox::receive_if(void* msg, int msg_size){
return rt_mbx_receive_if(m_Mailbox,msg,msg_size);
}
int Mailbox::receive_until(void* msg, int msg_size, const Count& time){
return rt_mbx_receive_until(m_Mailbox,msg,msg_size,time);
}
int Mailbox::receive_timed(void* msg, int msg_size, const Count& delay){
return rt_mbx_receive_timed(m_Mailbox,msg,msg_size,delay);
}
}; // namespace RTAI

117
addons/cpp/mbx.h Normal file
View file

@ -0,0 +1,117 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: mbx.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __MBX_H__
#define __MBX_H__
#include "rtai.h"
#include "rtai_sched.h"
#include "rtai_mbx.h"
#include "count.h"
namespace RTAI {
/**
* MBX wrapper class
*/
class Mailbox {
public:
Mailbox();
Mailbox(int size);
Mailbox(const char* name);
Mailbox(const char* name, int size);
virtual ~Mailbox();
bool init(int size);
bool init(const char* name);
bool init(const char* name, int size);
int send(const void* msg, int msg_size);
int send_wp(const void* msg, int msg_size);
int send_if(const void* msg, int msg_size);
int send_until(const void* msg, int msg_size, const Count& time);
int send_timed(const void* msg, int msg_size, const Count& delay);
int receive(void* msg, int msg_size);
int receive_wp(void* msg, int msg_size);
int receive_if(void* msg, int msg_size);
int receive_until(void* msg, int msg_size, const Count& time);
int receive_timed(void* msg, int msg_size, const Count& delay);
protected:
MBX* m_Mailbox;
bool m_Named;
bool m_Owner;
private:
Mailbox(const Mailbox&);
Mailbox& operator=(const Mailbox&);
};
/**
* templated Mailbox class
*/
template <class Type>
class MailboxT
: public Mailbox
{
public:
MailboxT(){}
MailboxT(int size):Mailbox(size){}
MailboxT(const char* name ):Mailbox(name){}
MailboxT(const char* name, int size):Mailbox(name,size){}
int send(const Type* msg){
return Mailbox::send(msg,sizeof(Type));
}
int send_wp(const Type* msg){
return Mailbox::send_wp(msg,sizeof(Type));
}
int send_if(const Type* msg){
return Mailbox::send_if(msg,sizeof(Type));
}
int send_until(const Type* msg, const Count& time){
return Mailbox::send_until(msg,sizeof(Type),time);
}
int send_timed(const Type* msg, const Count& delay){
return Mailbox::send_timed(msg,sizeof(Type),delay);
}
int receive(Type* msg){
return Mailbox::receive(msg,sizeof(Type));
}
int receive_wp(Type* msg){
return Mailbox::receive_wp(msg,sizeof(Type));
}
int receive_if(Type* msg){
return Mailbox::receive_if(msg,sizeof(Type));
}
int receive_until(Type* msg, const Count& time){
return Mailbox::receive_until(msg,sizeof(Type),time);
}
int receive_timed(Type* msg, const Count& delay){
return Mailbox::receive_timed(msg,sizeof(Type),delay);
}
};
}; // namespace RTAI
#endif

25
addons/cpp/module.cc Normal file
View file

@ -0,0 +1,25 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: module.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "module.h"

38
addons/cpp/module.h Normal file
View file

@ -0,0 +1,38 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: module.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __MODULE_H__
#define __MODULE_H__
namespace RTAI {
class Module {
public:
Module(){}
virtual ~Module(){}
};
}; // namespace RTAI
#endif

48
addons/cpp/mutex.cc Normal file
View file

@ -0,0 +1,48 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: mutex.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "mutex.h"
namespace RTAI {
Mutex::Mutex()
: Semaphore(1, RES_SEM)
{
}
Mutex::~Mutex(){
}
ScopedMutex::ScopedMutex( Mutex& m )
: m_Mutex( m )
{
m_Mutex.wait();
}
ScopedMutex::~ScopedMutex()
{
m_Mutex.signal();
}
};

66
addons/cpp/mutex.h Normal file
View file

@ -0,0 +1,66 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: mutex.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "rtai.h"
#include "time.h"
#include "sem.h"
#ifndef __MUTEX_H__
#define __MUTEX_H__
namespace RTAI {
/**
* mutal exclusion lock class
*/
class Mutex
: public Semaphore
{
friend class Condition;
public:
Mutex();
virtual ~Mutex();
private:
Mutex(const Mutex&);
Mutex& operator=(const Mutex&);
};
/**
* Scoped mutal exclusion lock class
*/
class ScopedMutex {
public:
ScopedMutex( Mutex& m );
~ScopedMutex();
protected:
Mutex& m_Mutex;
private:
ScopedMutex( const ScopedMutex& );
ScopedMutex operator=( const ScopedMutex& );
};
}; // namespace RTAI
#endif

64
addons/cpp/new.h Normal file
View file

@ -0,0 +1,64 @@
// The -*- C++ -*- dynamic memory management header.
// Copyright (C) 1994, 1996, 1997, 1998, 2000, 2001 Free Software Foundation
//
// This file is part of GNU CC.
//
// GNU CC 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, or (at your option)
// any later version.
//
// GNU CC 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 GNU CC; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
/** @file new
* This header defines several functions to manage dynamic memory and
* handling memory allocation errors; see
* http://gcc.gnu.org/onlinedocs/libstdc++/18_support/howto.html#4 for more.
*/
#ifndef __NEW_H__
#define __NEW_H__
extern "C++" {
//@{
/** These are replaceable signatures:
* - normal single new and delete (no arguments, throw @c bad_alloc on error)
* - normal array new and delete (same)
* - @c nothrow single new and delete (take a @c nothrow argument, return
* @c NULL on error)
* - @c nothrow array new and delete (same)
*
* Placement new and delete signatures (take a memory address argument,
* does nothing) may not be replaced by a user's program.
*/
void *operator new(unsigned int);
void *operator new[](unsigned int);
void operator delete(void *);
void operator delete[](void *);
// Default placement versions of operator new.
inline void *operator new(unsigned int, void *place) { return place; }
inline void *operator new[](unsigned int, void *place) { return place; }
//@}
} // extern "C++"
#endif

53
addons/cpp/rtai_cpp.h Normal file
View file

@ -0,0 +1,53 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtai_cpp.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __RTAI_CPP_H__
#define __RTAI_CPP_H__
#ifdef __cplusplus
// for C++ only
#include <rtai_sched.h>
extern RT_TASK* __rt_task_init(void (*rt_thread)(int), int data,
int stack_size, int priority, int uses_fpu,
void(*signal)(void));
extern int __rt_task_delete(RT_TASK *task);
#endif
/* for both C and C++ */
#ifdef __cplusplus
extern "C" {
#endif
extern void init_cpp( void );
extern void cleanup_cpp( void );
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,272 @@
#ifndef _RTAI_PQUEUE_WRAPPER_H
#define _RTAI_PQUEUE_WRAPPER_H
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (©) 1999 Zentropic Computing, All rights reserved
//
// Authors: Trevor Woolven (trevw@zentropix.com)
// Original date: Thu 15 Jul 1999
// Id: @(#)$Id: rtai_pqueue_wrapper.h,v 1.4 2013/10/22 14:54:14 ando Exp $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// pqueues interface for Real Time Linux.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
#include "linux_wrapper.h"
#include "rtai.h"
#include "rtai_pthread_wrapper.h"
#include "zdefs.h"
// ----------------------------------------------------------------------------
#define TASK_FPU_DISABLE 0
#define TASK_FPU_ENABLE 1
//Posix definitions
#define MQ_OPEN_MAX 8 //Maximum number of message queues per process
#define MQ_PRIO_MAX 32 //Maximum number of message priorities
#define MQ_BLOCK 0 //Flag to set queue into blocking mode
#define MQ_NONBLOCK 1 //Flag to set queue into non-blocking mode
#define MQ_NAME_MAX 80 //Maximum length of a queue name string
#define MQ_MIN_MSG_PRIORITY 0 //Lowest priority message
#define MQ_MAX_MSG_PRIORITY MQ_PRIO_MAX //Highest priority message
//Definitions to support higher-level applications
typedef enum {FIFO_BASED, PRIORITY_BASED} QUEUEING_POLICY;
typedef enum {POSIX, VxWORKS} QUEUE_TYPE;
// ----------------------------------------------------------------------------
//Posix Queue Attributes
struct mq_attr {
long mq_maxmsg; //Maximum number of messages in queue
long mq_msgsize; //Maximum size of a message (in bytes)
long mq_flags; //Blocking/Non-blocking behaviour specifier
// not used in mq_open only relevant for
// mq_getattrs and mq_setattrs
long mq_curmsgs; //Number of messages currently in queue
};
typedef struct mq_attr MQ_ATTR;
typedef union sigval {
int sival_int;
void *sival_ptr;
} sigval_t;
/*
* sigevent definitions
*
* It seems likely that SIGEV_THREAD will have to be handled from
* userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
* thread manager then catches and does the appropriate nonsense.
* However, everything is written out here so as to not get lost.
*/
#define SIGEV_SIGNAL 0 /* notify via signal */
#define SIGEV_NONE 1 /* other notification: meaningless */
#define SIGEV_THREAD 2 /* deliver via thread creation */
#define SIGEV_MAX_SIZE 64
#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
typedef struct sigevent {
sigval_t sigev_value;
int sigev_signo;
int sigev_notify;
union {
int _pad[SIGEV_PAD_SIZE];
struct {
void (*_function)(sigval_t);
void *_attribute; /* really pthread_attr_t */
} _sigev_thread;
} _sigev_un;
} sigevent_t;
//Notification data
struct notify {
RT_TASK *task;
struct sigevent data;
};
// ----------------------------------------------------------------------------
//Generic Message format
//TODO: Consider moving this definition into rtai_utils.h
struct msg_hdr {
BOOL in_use;
size_t size; //Actual message size
uint priority; //Usage priority (message/task)
void *next; //Pointer to next message on queue
};
typedef struct msg_hdr MSG_HDR;
//Generic queue header
struct queue_control {
void *base; //Pointer to the base of the queue in memory
void *head; //Pointer to the element at the front of the queue
void *tail; //Pointer to the element at the back of the queue
MQ_ATTR attrs; //Queue attributes
};
typedef struct queue_control Q_CTRL;
//Data messages
struct msg {
MSG_HDR hdr;
char data; //Anchor point for message data
};
typedef struct msg MSG;
// ----------------------------------------------------------------------------
//Posix Queue Descriptors
struct _pqueue_descr_struct {
RT_TASK *owner; //Task that created the queue
int open_count; //Count of the number of tasks that have
// 'opened' the queue for access
char q_name[MQ_NAME_MAX]; //Name supplied for queue
uint q_id; //Queue Id (index into static list of queues)
BOOL marked_for_deletion; //Queue can be deleted once all tasks have
// closed it
Q_CTRL data; //Data queue (real messages)
mode_t permissions; //Permissions granted by creator (ugo, rwx)
struct notify notify; //Notification data (empty -> !empty)
pthread_cond_t emp_cond; //For blocking on empty queue
pthread_cond_t full_cond; //For blocking on full queue
pthread_mutex_t mutex; //For synchronisation of queue
};
typedef struct _pqueue_descr_struct MSG_QUEUE;
// ----------------------------------------------------------------------------
//Task-related Posix Queue data
//A task can open up to MQ_OPEN_MAX pqueues, each with 'potentially'
//different permissions (read, write, blocking/non-blocking etc)
//
struct _pqueue_access_data {
int q_id;
int oflags; //Queue access permissions & blocking spec
};
struct _pqueue_access_struct {
RT_TASK *this_task;
int n_open_pqueues;
struct _pqueue_access_data q_access[MQ_OPEN_MAX];
};
typedef struct _pqueue_access_struct *QUEUE_CTRL;
// ----------------------------------------------------------------------------
typedef unsigned long mqd_t;
#define INVALID_PQUEUE 0
typedef enum {FOR_READ, FOR_WRITE} Q_ACCESS;
///////////////////////////////////////////////////////////////////////////////
// ACCESS FUNCTIONS
///////////////////////////////////////////////////////////////////////////////
QUEUEING_POLICY get_task_queueing_policy(void);
QUEUEING_POLICY set_task_queuing_policy(QUEUEING_POLICY policy);
QUEUE_TYPE get_queue_type(void);
QUEUE_TYPE set_queue_type(QUEUE_TYPE type);
///////////////////////////////////////////////////////////////////////////////
// POSIX MESSAGE QUEUES API
//
// Note that error returns represent the appropriate macro found in errno.h
// eg: -EINVAL, -EBADF etc
//
///////////////////////////////////////////////////////////////////////////////
//--------------------------------< mq_open >----------------------------------
// Create and/or open a message queue
//
// Return codes: >= 0 valid Posix Queue Id
// < 0 error
//
extern mqd_t mq_open(char *mq_name, int oflags, mode_t permissions,
struct mq_attr *mq_attr);
//------------------------------< mq_receive >---------------------------------
// Receive a message from a message queue
//
// Return codes: >= 0 number of bytes received
// < 0 error
//
extern size_t mq_receive(mqd_t mq, char *msg_buffer,
size_t buflen, unsigned int *msgprio);
//--------------------------------< mq_send >----------------------------------
// Send a message to a queue
//
// Return codes: >= 0 number of bytes sent
// < 0 error
extern int mq_send(mqd_t mq, const char *msg, size_t msglen,
unsigned int msgprio);
//--------------------------------< mq_close >---------------------------------
// Close a message queue (note that the queue remains in existance!)
//
// Return codes: = 0 pQueue closed OK
// < 0 error
//
extern int mq_close(mqd_t mq);
//-------------------------------< mq_getattr >--------------------------------
// Get the attributes of a message queue
//
// Return codes: = 0 attributes copied successfully
// < 0 error
//
extern int mq_getattr(mqd_t mq, struct mq_attr *attrbuf);
//-------------------------------< mq_setattr >--------------------------------
// Set a subset of a message queue's attributes
//
// Return codes: = 0 attributes set successfully
// < 0 error
//
extern int mq_setattr(mqd_t mq, const struct mq_attr *new_attrs,
struct mq_attr *old_attrs);
//-------------------------------< mq_notify >---------------------------------
// Register a request to be notified whenever a message arrives on an empty
// queue
// Note that setting the 'notification' parameter to NULL cancels the task's
// earlier notification request
//
// Return codes: = 0 notification set/cleared successfully
// < 0 error
//
extern int mq_notify(mqd_t mq, const struct sigevent *notification);
//-------------------------------< mq_unlink >---------------------------------
// Destroy a message queue
//
// Returns: = 0 queue was successfully unlinked
// < 0 error
// > 0 'n' tasks still have the queue 'open'
//
extern int mq_unlink(char *mq_name);
// ---------------------------------< eof >------------------------------------
#ifdef __cplusplus
}
#endif
#endif // _RTAI_PQUEUE_WRAPPER_H_

View file

@ -0,0 +1,78 @@
#ifndef _RTAI_PTHREAD_INT_WRAPPER_H_
#define _RTAI_PTHREAD_INT_WRAPPER_H_
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (©) 1999 Zentropic Computing, All rights reserved
//
// Authors: Steve Papacharalambous (stevep@zentropix.com)
// Original date: Thu 15 Jul 1999
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// pthreads interface for Real Time Linux.
//
// Modified for wrapping the pthreads to rtai_cpp by Peter Soetens
//
///////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
// ----------------------------------------------------------------------------
#define POSIX_THREADS_MAX 64
#define PTHREAD_KEYS_MAX 1024
// Thread specific data is kept in a special data structure, a two-level
// array. The top-level array contains pointers to dynamically allocated
// arrays of a certain number of data pointers. So a sparse array can be
// implemented. Each dynamic second-level array has
// PTHREAD_KEY_2NDLEVEL_SIZE
// entries,and this value shouldn't be too large.
#define PTHREAD_KEY_2NDLEVEL_SIZE 32
// Need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
// keys in each subarray.
#define PTHREAD_KEY_1STLEVEL_SIZE \
((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
/ PTHREAD_KEY_2NDLEVEL_SIZE)
#define TASK_FPU_DISABLE 0
#define TASK_FPU_ENABLE 1
#define NSECS_PER_SEC 1000000000
// ----------------------------------------------------------------------------
// Arguments passed to thread creation routine.
struct pthread_start_args;
#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, 0, 0, { 0 } }
struct _pthread_descr_struct;
#ifdef __cplusplus
}
#endif
#endif // _RTAI_PTHREAD_INT_WRAPPER_H_

View file

@ -0,0 +1,304 @@
#ifndef _RTAI_PTHREAD_WRAPPER_H_
#define _RTAI_PTHREAD_WRAPPER_H_
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (©) 1999 Zentropic Computing, All rights reserved
//
// Authors: Steve Papacharalambous (stevep@zentropix.com)
// Original date: Thu 15 Jul 1999
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// pthreads interface for Real Time Linux.
//
// Modified for wrapping the pthreads to rtai_cpp by Peter Soetens
//
///////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
#include "linux_wrapper.h"
#include "rtai.h"
#include "rtai_pthread_int_wrapper.h"
#include "rtai_types.h"
// ----------------------------------------------------------------------------
typedef struct rt_task_struct RT_TASK;
#define SEM_ERR (0xffff) // MUST be the same as rtai_sched.c
#define RT_SEM_MAGIC 0xaabcdeff // MUST be the same as rtai_sched.c
// ----------------------------------------------------------------------------
#define PTHREAD_MUTEX_INITIALIZER {0, PTHREAD_MUTEX_FAST_NP, {{0, 0, 0}, RT_SEM_MAGIC, BIN_SEM, 1, 0, FIFO_Q}}
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, PTHREAD_MUTEX_RECURSIVE_NP, {{0, 0, 0}, RT_SEM_MAGIC, BIN_SEM, 1, 0, FIFO_Q}}
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP {0, PTHREAD_MUTEX_ERRORCHECK_NP, {{0, 0, 0}, RT_SEM_MAGIC, BIN_SEM, 1, 0, FIFO_Q}}
#define PTHREAD_COND_INITIALIZER {{{0, 0, 0}, RT_SEM_MAGIC, BIN_SEM, 1, 0, FIFO_Q}}
// ----------------------------------------------------------------------------
enum { PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE };
enum { PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS };
enum { PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED };
enum { PTHREAD_CREATE_JOINABLE, PTHREAD_CREATE_DETACHED };
enum { PTHREAD_SCOPE_SYSTEM, PTHREAD_SCOPE_PROCESS };
enum {
PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP
};
enum { CLOCK_REALTIME };
// ----------------------------------------------------------------------------
typedef unsigned long pthread_t;
typedef struct _pthread_descr_struct *pthread_descr;
typedef int rt_jmp_buf[6];
/* START by Peter Soetens */
struct sched_param {
int sched_priority;
};
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
struct rt_queue {
struct rt_queue *prev;
struct rt_queue *next;
struct rt_task_struct *task;
};
typedef struct rt_queue QUEUE;
struct rt_semaphore {
struct rt_queue queue; //must be first in struct
int magic;
int type;
int count;
struct rt_task_struct *owndby;
int qtype;
};
typedef struct rt_semaphore SEM;
/* END by Peter Soetens */
typedef struct {
int detachstate;
int schedpolicy;
struct sched_param schedparam;
int inheritsched;
int scope;
} pthread_attr_t;
typedef struct {
int mutexkind;
} pthread_mutexattr_t;
typedef struct {
int dummy;
} pthread_condattr_t;
typedef struct {
RT_TASK *m_owner;
int m_kind;
struct rt_semaphore m_semaphore;
} pthread_mutex_t;
typedef struct {
SEM c_waiting;
} pthread_cond_t;
// Cleanup buffer.
struct _pthread_cleanup_buffer {
void (*routine)(void *); // Function to call.
void *arg; // Its argument.
int canceltype; // Saved cancellation type.
struct _pthread_cleanup_buffer *prev; // Chaining of cleanup functions.
};
// ----------------------------------------------------------------------------
// Create a RT task with attributes ATTR, or default attributes if ATTR is NULL
// and call start function START_ROUTINE passing arguments ARG.
extern int pthread_create(pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
// Terminate the calling thread,
extern void pthread_exit(void *retval);
// Get the identifier of the current thread.
extern pthread_t pthread_self(void);
// Initialise thread attribute object, and fill it in with default values.
extern int pthread_attr_init(pthread_attr_t *attr);
// Destroy a thread attribute object.
extern int pthread_attr_destroy(pthread_attr_t *attr);
// Set the detach state for the thread.
extern int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
// Get the detach state for the thread.
extern int pthread_attr_getdetachstate(const pthread_attr_t *attr,
int *detachstate);
// Set the thread scheduling parameters.
extern int pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *param);
// Get the thread scheduling parameters.
extern int pthread_attr_getschedparam(const pthread_attr_t *attr,
struct sched_param *param);
// Set thread scheduling policy.
extern int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
// Get thread scheduling policy.
extern int pthread_attr_getschedpolicy(const pthread_attr_t *attr,
int *policy);
// Set thread scheduling inheritance.
extern int pthread_attr_setinheritsched(pthread_attr_t *attr,
int inherit);
// Get thread scheduling inheritance.
extern int pthread_attr_getinheritsched(const pthread_attr_t *attr,
int *inherit);
// Set thread scheduling scope.
extern int pthread_attr_setscope(pthread_attr_t *attr, int scope);
// Get thread scheduling scope.
extern int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
// Yield the processor.
extern int sched_yield(void);
// Get the current clock count. (Only CLOCK_REALTIME is currently supported)
extern void clock_gettime( int clockid, struct timespec *current_time);
// Delay the execution of the calling task for the time specified in req.
extern int nanosleep(const struct timespec *req, struct timespec *rem);
// Initialise mutex object.
extern int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr);
// Destroy mutex object.
extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
// Initialise mutex object attributes.
extern int pthread_mutexattr_init(pthread_mutexattr_t *attr);
// Destroy mutex object attributes.
extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
// Set mutex kind attribute.
extern int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind);
// Retrieve the current value of the mutex kind attribute.
extern int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr,
int *kind);
// Set thread scheduling parameters.
extern int pthread_setschedparam(pthread_t thread, int policy,
const struct sched_param *param);
// Get thread scheduling parameters.
extern int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
// Non blocking mutex lock.
extern int pthread_mutex_trylock(pthread_mutex_t *mutex);
// Blocking mutex lock.
extern int pthread_mutex_lock(pthread_mutex_t *mutex);
// Mutex unlock.
extern int pthread_mutex_unlock(pthread_mutex_t *mutex);
// Initialise conditional variable.
extern int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr);
// Destroy conditional variable.
extern int pthread_cond_destroy(pthread_cond_t *cond);
// Initialise condition attribute object.
extern int pthread_condattr_init(pthread_condattr_t *attr);
// Destroy condition attribute object.
extern int pthread_condattr_destroy(pthread_condattr_t *attr);
// Wait for condition variable to be signaled.
extern int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
// Wait for condition variable to be signaled or timeout expires.
extern int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime);
// Restart one of the threads waiting on the conditional variable cond.
extern int pthread_cond_signal(pthread_cond_t *cond);
// Restart all of the threads waiting on the conditional variable cond.
extern int pthread_cond_broadcast(pthread_cond_t *cond);
// ----------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif
#endif // _RTAI_PTHREAD_WRAPPER_H_

95
addons/cpp/rtai_wrapper.c Normal file
View file

@ -0,0 +1,95 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtai_wrapper.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "rtai_wrapper.h"
#include <rtai.h>
#include <rtai_malloc.h>
#include "tld_key.h"
void __rt_get_global_lock(void){
rt_get_global_lock();
}
void __rt_release_global_lock(void){
rt_release_global_lock();
}
int __hard_cpu_id( void ){
return hard_cpu_id();
}
/* task functions */
RT_TASK * __rt_task_init(void (*rt_thread)(int), int data,
int stack_size, int priority, int uses_fpu,
void(*signal)(void))
{
RT_TASK * task;
task = rt_malloc( sizeof(RT_TASK) );
if(task == 0)
return 0;
memset(task,0,sizeof(RT_TASK));
rt_task_init(task,rt_thread,data,stack_size,priority,uses_fpu,signal);
__rt_tld_set_data(task,cpp_key,(void*)data);
return task;
}
int __rt_task_delete(RT_TASK *task)
{
int result;
rt_printk("__rt_task_delete(%p)\n",task);
if(task == 0)
return -1;
rt_task_suspend(task);
result = rt_task_delete(task);
rt_free(task);
return result;
}
#ifdef CONFIG_RTAI_TRACE
void __trace_destroy_event( int id ){
trace_destroy_event( id );
}
int __trace_create_event( const char* name, void* p){
return trace_create_event( (char *)name, NULL, CUSTOM_EVENT_FORMAT_TYPE_NONE, (char *)p);
}
int __trace_raw_event( int id, int size, void* p){
return trace_raw_event( id, size, p);
}
#endif /* CONFIG_RTAI_TRACE */

49
addons/cpp/rtai_wrapper.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtai_wrapper.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __RTAI_WRAPPER_H__
#define __RTAI_WRAPPER_H__
/**
* The aim of this file is to contain all RTAI functions that can by no
* means be included with the C++ compiler.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <rtai_types.h>
void __rt_get_global_lock(void);
void __rt_release_global_lock(void);
int __hard_cpu_id(void);
#ifdef __cplusplus
}
#endif
#endif /* __RTAI_WRAPPER_H__ */

77
addons/cpp/rtf.cc Normal file
View file

@ -0,0 +1,77 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtf.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "rtf.h"
namespace RTAI {
RTAI::fifo* RTAI::fifo::m_this_table[MAX_FIFOS];
fifo::fifo(){
}
fifo::fifo(int id, int size){
create(id,size);
}
int fifo::create(int id, int size){
int res = rtf_create(id,size);
m_fifo = id;
m_this_table[id] = this;
return res;
}
fifo::~fifo(){
if(m_fifo != -1){
m_this_table[m_fifo] = 0;
rtf_destroy(m_fifo);
}
}
int fifo::reset(){
return rtf_reset(m_fifo);
}
int fifo::resize(int size){
return rtf_resize(m_fifo,size);
}
int fifo::put(const void* buffer, int count){
return rtf_put(m_fifo,const_cast<void*>(buffer),count);
}
int fifo::get(void* buffer, int count){
return rtf_get(m_fifo,buffer,count);
}
int fifo::activate_handler(){
return -1;
}
int fifo::deactivate_handler(){
return -1;
}
}; // namespace RTAI

78
addons/cpp/rtf.h Normal file
View file

@ -0,0 +1,78 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtf.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __RTF_H__
#define __RTF_H__
#include "rtai.h"
#include "rtai_fifos.h"
namespace RTAI {
/**
* RTF wrapper class
*/
class fifo {
public:
fifo();
fifo(int id, int size);
virtual ~fifo();
int create(int id, int size);
int reset();
int resize(int size);
int put(const void* buffer, int count);
int get(void* buffer, int count);
int activate_handler();
int deactivate_handler();
virtual void handler(){};
protected:
int m_fifo;
static fifo* m_this_table[MAX_FIFOS];
};
template <class Type>
class fifoT
: public fifo
{
public:
fifoT(){}
fifoT(int id,int size) : fifo(id,size){}
int put(const Type* type) {
return fifo::put((const void*)type,sizeof(Type));
}
int get(Type* type) {
return fifo::get((void*)type,sizeof(Type));
}
};
};
#endif

51
addons/cpp/rtf_init.c Normal file
View file

@ -0,0 +1,51 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: rtf_init.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <rtai_malloc.h>
#include "rtai.h"
// RTAI-- MODULE INIT and CLEANUP functions
MODULE_LICENSE("GPL");
MODULE_AUTHOR("the RTAI-Team (contact person Erwin Rol)");
MODULE_DESCRIPTION("RTAI C++ RTF support");
int __init rtai_cpp_rtf_init(void){
return 0;
}
void rtai_cpp_rtf_cleanup(void)
{
}
module_init(rtai_cpp_rtf_init)
module_exit(rtai_cpp_rtf_cleanup)

112
addons/cpp/sem.cc Normal file
View file

@ -0,0 +1,112 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: sem.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "sem.h"
#include "rtai_registry.h"
namespace RTAI {
Semaphore::Semaphore(int value, int type){
m_Owner = true;
m_Named = false;
rt_typed_sem_init(m_Sem, value,type);
}
Semaphore::Semaphore(const char* name, int value, int type){
m_Owner = true;
m_Named = true;
m_Sem = rt_typed_named_sem_init(name,value,type);
}
Semaphore::Semaphore(const char* name){
m_Named = true;
m_Owner = false;
m_Sem = 0;
unsigned long num = nam2num(name);
if( rt_get_type( num ) == IS_SEM ){
m_Sem = static_cast<SEM*>( rt_get_adr( num ) );
}
}
Semaphore::~Semaphore(){
if(m_Sem != 0){
if( m_Owner ){
if( m_Named )
rt_named_sem_delete(m_Sem);
else
rt_sem_delete(m_Sem);
}
}
}
int Semaphore::signal(){
return rt_sem_signal(m_Sem);
}
int Semaphore::broadcast(){
return rt_sem_broadcast(m_Sem);
}
int Semaphore::wait(){
return rt_sem_wait(m_Sem);
}
int Semaphore::wait_if(){
return rt_sem_wait_if(m_Sem);
}
int Semaphore::wait_until(const Time& time){
return rt_sem_wait_until(m_Sem,time.to_count());
}
int Semaphore::wait_timed(const Time& delay){
return rt_sem_wait_timed(m_Sem,delay.to_count());
}
BinarySemaphore::BinarySemaphore()
: Semaphore(0,BIN_SEM)
{
}
BinarySemaphore::~BinarySemaphore(){
}
CountingSemaphore::CountingSemaphore()
: Semaphore(0,CNT_SEM)
{
}
CountingSemaphore::~CountingSemaphore(){
}
ResourceSemaphore::ResourceSemaphore()
: Semaphore(0,RES_SEM)
{
}
ResourceSemaphore::~ResourceSemaphore(){
}
};

106
addons/cpp/sem.h Normal file
View file

@ -0,0 +1,106 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: sem.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "rtai_sched.h"
#include "rtai_sem.h"
#include "time.h"
#ifndef __SEM_H__
#define __SEM_H__
namespace RTAI {
/**
* Abstract Semaphore base class.
*/
class Semaphore {
protected:
Semaphore(int value,int type);
Semaphore(const char* name, int value, int type);
Semaphore(const char* name );
public:
virtual ~Semaphore();
int signal();
int broadcast();
int wait();
int wait_if();
int wait_until(const Time& time);
int wait_timed(const Time& delay);
protected:
SEM* m_Sem;
bool m_Owner;
bool m_Named;
private:
Semaphore(const Semaphore&);
Semaphore& operator=(const Semaphore&);
};
/**
* Binary Semaphore class
*/
class BinarySemaphore
: public Semaphore
{
public:
BinarySemaphore();
virtual ~BinarySemaphore();
protected:
private:
BinarySemaphore(const BinarySemaphore&);
BinarySemaphore& operator=(const BinarySemaphore&);
};
/**
* Counting Semaphore class
*/
class CountingSemaphore
: public Semaphore
{
public:
CountingSemaphore();
virtual ~CountingSemaphore();
protected:
private:
CountingSemaphore(const CountingSemaphore&);
CountingSemaphore& operator=(const CountingSemaphore&);
};
/**
* Resource Semaphore class
*/
class ResourceSemaphore
: public Semaphore
{
public:
ResourceSemaphore();
~ResourceSemaphore();
protected:
private:
ResourceSemaphore(const ResourceSemaphore&);
ResourceSemaphore& operator=(const ResourceSemaphore&);
};
}; // namesapce RTAI
#endif

336
addons/cpp/task.cc Normal file
View file

@ -0,0 +1,336 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: task.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "task.h"
#include "iostream.h"
#include "tld_key.h"
#include <asm/rtai.h>
#include <rtai_registry.h>
#include <rtai_wrapper.h>
extern "C" {
// OK, this is _ugly_, int casting to this* is even
// worse than casting a void* to a this* (like with pthreads)
void entry_point(int this_pointer){
RTAI::Task* This = (RTAI::Task*)this_pointer;
This->run();
}
}
void signal_handler(){
#if 0
RTAI::Task* This = RTAI::Task::self();
This->signal_handler();
#endif
}
namespace RTAI {
void get_global_lock(void){
__rt_get_global_lock();
}
void release_global_lock(void){
__rt_release_global_lock();
}
int hard_cpu_id(void){
return hard_cpu_id();
}
int assign_irq_to_cpu(int irq, unsigned long cpus_mask){
return rt_assign_irq_to_cpu(irq,cpus_mask);
}
int reset_irq_to_sym_mode(int irq){
return rt_reset_irq_to_sym_mode(irq);
}
void set_oneshot_mode(void){
rt_set_oneshot_mode();
}
void set_periodic_mode(void){
rt_set_periodic_mode();
}
Count start_timer(void){
return Count( start_rt_timer(0) );
}
Count start_timer(const Count& period){
return Count( start_rt_timer( period ) );
}
void stop_timer(void){
stop_rt_timer();
}
void linux_use_fpu(bool use_fpu_flag){
rt_linux_use_fpu(use_fpu_flag);
}
void preempt_always(bool yes_no){
rt_preempt_always(yes_no);
}
void preempt_always_cpuid(bool yes_no, unsigned int cpu_id){
rt_preempt_always_cpuid(yes_no,cpu_id);
}
/////////////////////////////////////////////
// class RTAI::Task
//
Task::Task(){
std::cerr << "Task::Task() " << (void*)this << std::endl;
m_TaskOwner = false;
m_Named = false;
m_Task = 0;
for(int n=0; n < CONFIG_RTAI_CPUS;n++)
m_CpuUse[n] = 0;
}
Task::~Task(){
std::cerr << "Task::~Task() " << (void*)this << std::endl;
if(m_Task != 0)
{
if( m_TaskOwner ){
if( m_Named){
rt_named_task_delete(m_Task);
} else {
rt_task_delete(m_Task);
}
}
}
}
Task::Task(int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid)
{
std::cerr << "Task::Task(...) " << (void*)this << std::endl;
m_TaskOwner = true;
m_Named = false;
m_Task = 0;
for(int n=0; n < CONFIG_RTAI_CPUS;n++)
m_CpuUse[n] = 0;
init(stack_size,priority,uses_fpu,use_signal,cpuid);
}
Task::Task(const char* name,
int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid)
{
std::cerr << "Task::Task(...) " << (void*)this << std::endl;
m_Named = true;
m_TaskOwner = true;
m_Task = 0;
for(int n=0; n < CONFIG_RTAI_CPUS;n++)
m_CpuUse[n] = 0;
init(name,stack_size,priority,uses_fpu,use_signal,cpuid);
}
Task::Task(const char* name )
{
std::cerr << "Task::Task(...) " << (void*)this << std::endl;
m_Named = true;
m_TaskOwner = false;
m_Task = 0;
for(int n=0; n < CONFIG_RTAI_CPUS;n++)
m_CpuUse[n] = 0;
init( name );
}
bool Task::init(int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid)
{
rt_printk("Task::init(...) %p\n",this);
if(m_Task != 0)
return false;
m_Named = false;
m_TaskOwner = true;
if(stack_size == 0)
stack_size = 1024*4;
if(use_signal)
rt_task_init(m_Task, ::entry_point,(int)this,
stack_size,priority,uses_fpu,::signal_handler);
else
rt_task_init(m_Task, ::entry_point,(int)this,
stack_size,priority,uses_fpu,0);
return true;
}
bool Task::init(const char* name,
int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid)
{
rt_printk("Task::init(...) %p\n",this);
if(m_Task != 0)
return false;
m_Named = true;
m_TaskOwner = true;
if(stack_size == 0)
stack_size = 1024*4;
if(use_signal)
m_Task = rt_named_task_init(name, ::entry_point,(int)this,
stack_size,priority,uses_fpu,::signal_handler);
else
m_Task = rt_named_task_init(name, ::entry_point,(int)this,
stack_size,priority,uses_fpu,0);
if( m_Task == 0)
return false;
return true;
}
bool Task::init(const char* name)
{
rt_printk("Task::init(...) %p\n",this);
if(m_Task != 0)
return false;
m_Named = true;
m_TaskOwner = false;
unsigned long num = nam2num(name);
if( rt_get_type( num ) == IS_TASK ){
m_Task = static_cast<RT_TASK*>( rt_get_adr( num ) );
}
if( m_Task == 0)
return false;
return true;
}
#if 0
Task* Task::self(){
struct rt_task_struct* task = rt_whoami();
if(task == 0)
return 0;
return (Task*)__rt_tld_get_data(task,cpp_key);
}
#endif
void Task::suspend(){
rt_task_suspend(m_Task);
}
void Task::resume(){
rt_task_resume(m_Task);
}
void Task::yield(){
rt_task_yield();
}
int Task::make_periodic(const Count& start_time, const Count& period){
return rt_task_make_periodic(m_Task,start_time, period );
}
int Task::make_periodic_relative(const Time& start_delay, const Time& period){
return rt_task_make_periodic_relative_ns(m_Task,start_delay, period);
}
void Task::set_runnable_on_cpus(unsigned int cpu_mask){
rt_set_runnable_on_cpus(m_Task,cpu_mask);
}
void Task::set_runnable_on_cpuid(unsigned int cpuid){
rt_set_runnable_on_cpuid(m_Task,cpuid);
}
void Task::wait_period(){
rt_task_wait_period();
}
void Task::busy_sleep(const Time& time){
rt_busy_sleep((long long)time);
}
void Task::sleep(const Count& delay){
rt_sleep( delay );
}
void Task::sleep_until(const Count& count){
rt_sleep_until( count );
}
int Task::use_fpu(bool use_fpu_flag){
return rt_task_use_fpu(m_Task,use_fpu_flag);
}
bool Task::is_valid(){
return (m_Task != 0);
}
void Task::inc_cpu_use(){
m_CpuUse[ RTAI::hard_cpu_id() ]++;
}
void Task::dump_cpu_use()
{
int cpuid;
// Output some statistics about CPU usage
std::cerr << "\n\nCPU USE SUMMARY\n";
for (cpuid = 0; cpuid < CONFIG_RTAI_CPUS; cpuid++) {
std::cerr << "# " << cpuid << " -> " << m_CpuUse[ cpuid ] << std::endl;
}
std::cerr << "END OF CPU USE SUMMARY\n\n";
}
}; // namespace RTAI

137
addons/cpp/task.h Normal file
View file

@ -0,0 +1,137 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: task.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __TASK_H__
#define __TASK_H__
#include "rtai_config.h"
#include "rtai.h"
#include "rtai_sched.h"
#include "time.h"
#include "count.h"
extern "C" void entry_point(int this_pointer);
extern "C" void signal_handler(void);
namespace RTAI {
extern void get_global_lock(void);
extern void release_global_lock(void);
extern int hard_cpu_id(void);
extern int assign_irq_to_cpu(int irq, unsigned long cpus_mask);
extern int reset_irq_to_sym_mode(int irq);
extern void set_oneshot_mode(void);
extern void set_periodic_mode(void);
extern Count start_timer(void);
extern Count start_timer(const Count& period);
extern void stop_timer(void);
extern void linux_use_fpu(bool use_fpu_flag);
extern void preempt_always(bool yes_no);
extern void preempt_always_cpuid(bool yes_no, unsigned int cpu_id);
/**
* Task wrapper class
*/
class Task {
friend void entry_point(int this_pointer);
public:
Task();
Task(int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid);
Task(const char* name,
int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid);
Task(const char* name );
virtual ~Task();
virtual bool init(int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid);
virtual bool init(const char* name,
int stack_size,
int priority,
bool uses_fpu,
bool use_signal,
unsigned int cpuid);
virtual bool init(const char* name);
#if 0
static Task* self();
#endif
static void yield();
void suspend();
void resume();
virtual int make_periodic(const Count& start_time, const Count& period);
virtual int make_periodic_relative(const Time& start_delay, const Time& period);
static void wait_period();
static void busy_sleep(const Time& time);
static void sleep(const Count& delay);
static void sleep_until(const Count& count);
int use_fpu(bool use_fpu_flag);
void set_runnable_on_cpus(unsigned int cpu_mask);
void set_runnable_on_cpuid(unsigned int cpuid);
virtual void signal_handler(){}
virtual int run() = 0;
bool is_valid();
void inc_cpu_use();
void dump_cpu_use();
protected:
int m_CpuUse[ CONFIG_RTAI_CPUS ];
bool m_Named;
// true if this task object is the owner of the m_Task RT_TASK*
bool m_TaskOwner;
RT_TASK* m_Task;
}; // class Task
// global functions inside RTAI:: namespace
}; // namespace RTAI
#endif

177
addons/cpp/tbx.cc Normal file
View file

@ -0,0 +1,177 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: tbx.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "tbx.h"
#include "iostream.h"
namespace RTAI {
TypedMailbox::TypedMailbox()
{
rt_printk("TypedMailbox::TypedMailbox() %p\n",this);
m_TypedMailbox = 0;
m_Owner = true;
m_Named = false;
}
TypedMailbox::TypedMailbox(int size, int flags)
{
rt_printk("TypedMailbox::TypedMailbox( int size=%d, int flags=%d) %p\n",size,flags,this);
m_TypedMailbox = 0;
m_Owner = true;
m_Named = false;
init( size , flags );
}
TypedMailbox::TypedMailbox(const char* name)
{
m_TypedMailbox = 0;
m_Named = true;
m_Owner = false;
init( name );
}
TypedMailbox::TypedMailbox(const char* name, int size, int flags)
{
m_TypedMailbox = 0;
m_Named = true;
m_Owner = true;
init(name,size,flags);
}
TypedMailbox::~TypedMailbox()
{
rt_printk("TypedMailbox::~TypedMailbox() %p\n",this);
if(m_TypedMailbox != 0){
if( m_Owner ){
if( m_Named ) {
// nothing yet
} else {
rt_tbx_delete(m_TypedMailbox);
}
}
}
}
void TypedMailbox::init(int size, int flags )
{
rt_printk("TypedMailbox::init(int size=%d, int flags=%d) %p\n",size,flags,this);
if(m_TypedMailbox == 0)
rt_tbx_init(m_TypedMailbox, size,flags);
}
void TypedMailbox::init(const char* name )
{
std::cerr << "TypedMailbox::init(name) NOT IMPLEMENTED" << std::endl;
}
void TypedMailbox::init(const char* name, int size, int flags )
{
std::cerr << "TypedMailbox::init(name,size,flags) NOT IMPLEMENTED" << std::endl;
}
int TypedMailbox::send( void *msg, int msg_size )
{
return rt_tbx_send( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::send_if( void *msg, int msg_size )
{
return rt_tbx_send_if( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::send_until( void *msg, int msg_size, const Count& time)
{
return rt_tbx_send_until( m_TypedMailbox, msg, msg_size, time );
}
int TypedMailbox::send_timed( void *msg, int msg_size, const Count& delay)
{
return rt_tbx_send_timed( m_TypedMailbox, msg, msg_size, delay );
}
int TypedMailbox::receive( void *msg, int msg_size)
{
return rt_tbx_receive( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::receive_if( void *msg, int msg_size)
{
return rt_tbx_receive_if( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::receive_until( void *msg, int msg_size, const Count& time)
{
return rt_tbx_receive_until( m_TypedMailbox, msg, msg_size, time );
}
int TypedMailbox::receive_timed( void *msg, int msg_size, const Count& delay)
{
return rt_tbx_receive_timed( m_TypedMailbox, msg, msg_size, delay );
}
int TypedMailbox::broadcast( void *msg, int msg_size)
{
return rt_tbx_broadcast( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::broadcast_if( void *msg, int msg_size)
{
return rt_tbx_broadcast_if( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::broadcast_until( void *msg, int msg_size, const Count& time)
{
return rt_tbx_broadcast_until( m_TypedMailbox, msg, msg_size, time);
}
int TypedMailbox::broadcast_timed( void *msg, int msg_size, const Count& delay)
{
return rt_tbx_broadcast_timed( m_TypedMailbox, msg, msg_size, delay );
}
int TypedMailbox::urgent( void *msg, int msg_size)
{
return rt_tbx_urgent( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::urgent_if( void *msg, int msg_size)
{
return rt_tbx_urgent_if( m_TypedMailbox, msg, msg_size );
}
int TypedMailbox::urgent_until( void *msg, int msg_size, const Count& time)
{
return rt_tbx_urgent_until( m_TypedMailbox, msg, msg_size, time );
}
int TypedMailbox::urgent_timed( void *msg, int msg_size, const Count& delay)
{
return rt_tbx_urgent_timed( m_TypedMailbox, msg, msg_size, delay );
}
}; // namespace RTAI

159
addons/cpp/tbx.h Normal file
View file

@ -0,0 +1,159 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: tbx.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __TBX_H__
#define __TBX_H__
#include "rtai.h"
#include "rtai_tbx.h"
#include "count.h"
namespace RTAI {
/**
* Typed Mailbox wrapper class
*/
class TypedMailbox {
public:
TypedMailbox();
TypedMailbox(int size, int flags);
TypedMailbox(const char* name);
TypedMailbox(const char* name, int size, int flags);
virtual ~TypedMailbox();
void init(int size, int flags );
void init(const char* name );
void init(const char* name, int size, int flags );
int send( void *msg, int msg_size );
int send_if( void *msg, int msg_size );
int send_until( void *msg, int msg_size, const Count& time);
int send_timed( void *msg, int msg_size, const Count& delay);
int receive( void *msg, int msg_size);
int receive_if( void *msg, int msg_size);
int receive_until( void *msg, int msg_size, const Count& time);
int receive_timed( void *msg, int msg_size, const Count& delay);
int broadcast( void *msg, int msg_size);
int broadcast_if( void *msg, int msg_size);
int broadcast_until( void *msg, int msg_size, const Count& time);
int broadcast_timed( void *msg, int msg_size, const Count& delay);
int urgent( void *msg, int msg_size);
int urgent_if( void *msg, int msg_size);
int urgent_until( void *msg, int msg_size, const Count& time);
int urgent_timed( void *msg, int msg_size, const Count& delay);
protected:
TBX* m_TypedMailbox;
bool m_Owner;
bool m_Named;
private:
TypedMailbox(const TypedMailbox&);
TypedMailbox& operator=(const TypedMailbox&);
};
/**
* templated Typed Mailbox wrapper class
*/
template <class Type>
class TypedMailboxT
: public TypedMailbox
{
public:
TypedMailboxT(){}
TypedMailboxT(int size, int flags):TypedMailbox(size,flags){}
TypedMailboxT(const char* name ):TypedMailbox(name){}
TypedMailboxT(const char* name, int size, int flags ):TypedMailbox(name,size,flags){}
int send( Type *msg ){
return TypedMailbox::send( (void*)msg, sizeof( Type ) );
}
int send_if( Type *msg ){
return TypedMailbox::send_if( (void*)msg, sizeof( Type ) );
}
int send_until( Type *msg, const Count& time){
return TypedMailbox::send_until( (void*)msg, sizeof( Type ), time );
}
int send_timed( Type *msg, const Count& delay){
return TypedMailbox::send_timed( (void*)msg, sizeof( Type ), delay );
}
int receive( Type *msg ){
return TypedMailbox::receive( (void*)msg, sizeof( Type ));
}
int receive_if( Type *msg ){
return TypedMailbox::receive_if( (void*)msg, sizeof( Type ) );
}
int receive_until( Type *msg, const Count& time){
return TypedMailbox::receive_until( (void*)msg, sizeof( Type ), time );
}
int receive_timed( Type *msg, const Count& delay){
return TypedMailbox::receive_timed((void*)msg, sizeof( Type ), delay );
}
int broadcast( Type *msg ){
return TypedMailbox::broadcast( (void*)msg, sizeof( Type ) );
}
int broadcast_if( Type *msg ){
return TypedMailbox::broadcast_if( (void*)msg, sizeof( Type ) );
}
int broadcast_until( Type *msg, const Count& time){
return TypedMailbox::broadcast_until( (void*)msg, sizeof( Type ), time );
}
int broadcast_timed( Type *msg, const Count& delay){
return TypedMailbox::broadcast_timed( (void*)msg, sizeof( Type ), delay );
}
int urgent( Type *msg ){
return TypedMailbox::urgent( (void*)msg, sizeof( Type ) );
}
int urgent_if( Type *msg ){
return TypedMailbox::urgent_if( (void*)msg, sizeof( Type ) );
}
int urgent_until( Type *msg, const Count& time){
return TypedMailbox::urgent_until( (void*)msg, sizeof( Type ), time );
}
int urgent_timed( Type *msg, const Count& delay){
return TypedMailbox::urgent_timed( (void*)msg, sizeof( Type ), delay );
}
};
}; // namespace RTAI
#endif

83
addons/cpp/tbx_init.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: tbx_init.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <rtai_tbx.h>
#include <rtai_malloc.h>
TBX* __rt_tbx_init(int size, int flags)
{
TBX * tbx;
tbx = rt_malloc(sizeof(TBX));
if(tbx == 0)
return 0;
memset(tbx,0,sizeof(TBX));
rt_tbx_init(tbx,size,flags);
return tbx;
}
int __rt_tbx_delete(TBX *tbx)
{
int result;
if(tbx == 0)
return -1;
result = rt_tbx_delete(tbx);
rt_free(tbx);
return result;
}
// RTAI-- MODULE INIT and CLEANUP functions
MODULE_LICENSE("GPL");
MODULE_AUTHOR("the RTAI-Team (contact person Erwin Rol)");
MODULE_DESCRIPTION("RTAI C++ TBX support");
int __init rtai_cpp_tbx_init(void){
return 0;
}
void rtai_cpp_tbx_cleanup(void)
{
}
module_init(rtai_cpp_tbx_init)
module_exit(rtai_cpp_tbx_cleanup)

142
addons/cpp/time.cc Normal file
View file

@ -0,0 +1,142 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: time.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "time.h"
#include "rtai_sched.h"
namespace RTAI {
Time::Time(){
m_Time = 0;
}
Time::Time(const Time& time)
: m_Time(time.m_Time)
{
}
Time::Time(long long time)
: m_Time(time)
{
}
Time& Time::operator=(const Time& time)
{
m_Time = time.m_Time;
return *this;
}
Time& Time::operator=(long long time)
{
m_Time = time;
return *this;
}
Time Time::now(){
return Time( count2nano( rt_get_time() ) );
}
Time Time::end(){
return Time(0x7FFFFFFFFFFFFFFFLL);
}
long long Time::to_count() const {
return nano2count(m_Time);
}
Time Time::from_count(long long count) {
Time tmp( count2nano(count) );
return tmp;
}
bool Time::operator==(const Time& time) const
{
return m_Time == time.m_Time;
}
bool Time::operator==(long long time) const
{
return m_Time == time;
}
bool Time::operator<(const Time& time)const{
return m_Time < time.m_Time;
}
bool Time::operator>(const Time& time)const {
return m_Time > time.m_Time;
}
bool Time::operator<=(const Time& time)const{
return m_Time <= time.m_Time;
}
bool Time::operator>=(const Time& time)const {
return m_Time >= time.m_Time;
}
Time& Time::operator+=(const Time& time){
m_Time += time.m_Time;
return *this;
}
Time& Time::operator+=(long long time) {
m_Time += time;
return *this;
}
Time& Time::operator-=(const Time& time) {
m_Time -= time.m_Time;
return *this;
}
Time& Time::operator-=(long long time){
m_Time -= time;
return *this;
}
Time Time::operator+(const Time& time) const {
Time tmp(m_Time + time.m_Time);
return tmp;
}
Time Time::operator+(long long time) const {
Time tmp(m_Time + time);
return tmp;
}
Time Time::operator-(const Time& time) const {
Time tmp(m_Time - time.m_Time);
return tmp;
}
Time Time::operator-(long long time) const {
Time tmp(m_Time - time);
return tmp;
}
}; // namespace RTAI

124
addons/cpp/time.h Normal file
View file

@ -0,0 +1,124 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: time.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "rtai.h"
#ifndef __TIME_H__
#define __TIME_H__
namespace RTAI {
/**
* time wrapper class
*
* Time keeps time in nanoseconds.
*/
class Time {
public:
/**
* The count ticks
*/
typedef long long ticks;
/**
* The time in nanoseconds
*/
typedef long long nsecs;
/**
* Initialise a time instance denoting zero nanoseconds
*/
Time();
/**
* Make a deep copy of a Time instance
*/
Time(const Time& time);
/**
* Initialise a time instance with <time>
*
* @param time The time in nanoseconds
*/
explicit Time(nsecs time);
Time& operator=(const Time& time);
Time& operator=(nsecs time);
/**
* Returns the current system time in nanoseconds
*/
static Time now();
/**
* Returns the largest system time (==infinity)
*/
static Time end();
inline operator nsecs() const { return m_Time; }
/**
* Converts this Time to internal system count units
*/
ticks to_count() const;
/**
* Factory Method. Creates a time instance from
* with a time converted from system count units
* to nanoseconds
*
* @param The system time in count units
*/
static Time from_count(ticks count);
bool operator==(const Time& time) const;
bool operator==(nsecs time) const;
inline bool operator!=(const Time& time) const { return !this->operator==(time); }
inline bool operator!=(nsecs time) const { return !this->operator==(time); }
bool operator<(const Time& time)const;
bool operator>(const Time& time)const;
bool operator<=(const Time& time)const;
bool operator>=(const Time& time)const;
Time& operator+=(const Time& time);
Time& operator+=(nsecs time);
Time& operator-=(const Time& time);
Time& operator-=(nsecs time);
Time operator+(const Time& time) const;
Time operator+(nsecs time) const;
Time operator-(const Time& time) const;
Time operator-(nsecs time) const;
protected:
nsecs m_Time; // nanosecs
};
}; // namespace RTAI
#endif

81
addons/cpp/tld_key.c Normal file
View file

@ -0,0 +1,81 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: tld_key.c,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "tld_key.h"
#include "rtai.h"
#if 0
void __rt_get_global_lock(void){
rt_get_global_lock();
}
void __rt_release_global_lock(void){
rt_release_global_lock();
}
int __hard_cpu_id( void ){
return hard_cpu_id();
}
#endif
int cpp_key;
// get a new key and mark it in tld_used_mask
int __rt_tld_create_key(void){
#if 1
return 0;
#else
return rt_tld_create_key();
#endif
}
// free the bit in tld_used_mask
int __rt_tld_free_key(int key){
#if 1
return 0;
#else
return rt_tld_free_key(key);
#endif
}
// set the data in the currents RT_TASKS tld_data array
int __rt_tld_set_data(RT_TASK *task,int key,void* data){
#if 1
task->system_data_ptr = (void*)data;
return 0;
#else
return rt_tld_set_data(task,key,data);
#endif
}
// get the data from the current task
void* __rt_tld_get_data(RT_TASK *task,int key){
#if 1
return (void*)task->system_data_ptr;
#else
return rt_tld_get_data(task,key);
#endif
}

55
addons/cpp/tld_key.h Normal file
View file

@ -0,0 +1,55 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: tld_key.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __TLD_KEY_H__
#define __TLD_KEY_H__
#include "rtai_sched.h"
#ifdef __cplusplus
extern "C" {
#endif
extern int cpp_key;
#if 0
void rt_get_global_lock(void);
void rt_release_global_lock(void);
#endif
int __rt_tld_create_key(void);
int __rt_tld_free_key(int key);
int __rt_tld_set_data(RT_TASK *task,int key,void* data);
void * __rt_tld_get_data(RT_TASK *task,int key);
#ifdef __cplusplus
}
#endif
#endif

61
addons/cpp/trace.cc Normal file
View file

@ -0,0 +1,61 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: trace.cc,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "trace.h"
namespace RTAI {
TraceEvent::TraceEvent()
{
m_ID = -1;
}
TraceEvent::TraceEvent( const char* name, void* p1, void* p2)
{
init( name, p1, p2 );
}
TraceEvent::~TraceEvent()
{
#ifdef CONFIG_RTAI_TRACE
if( m_ID != -1 )
__trace_destroy_event(m_ID);
#endif
}
void TraceEvent::init( const char* name, void* p1, void* p2)
{
#ifdef CONFIG_RTAI_TRACE
m_ID = __trace_create_event(name, p1, p2);
#endif
}
void TraceEvent::trigger( int size, void* data )
{
#ifdef CONFIG_RTAI_TRACE
__trace_raw_event(m_ID, size, data );
#endif
}
}; // namespace RTAI

73
addons/cpp/trace.h Normal file
View file

@ -0,0 +1,73 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: trace.h,v 1.4 2013/10/22 14:54:14 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __TRACE_H__
#define __TRACE_H__
#include <rtai_config.h>
namespace RTAI {
/**
* Trace toolkit wrapper class
*/
class TraceEvent
{
public:
TraceEvent();
TraceEvent( const char* name, void*, void* );
~TraceEvent();
void init( const char* name, void*, void* );
void trigger( int size, void* data );
protected:
int m_ID;
};
}; // namespace RTAI
#ifndef CONFIG_RTAI_TRACE
#warning included trace.h but no support in kernel for tracing
#else
#ifdef __cplusplus
extern "C" {
#endif
void __trace_destroy_event(int id);
int __trace_create_event(const char *name,
void *p1,
void *p2);
int __trace_raw_event(int id,
int size,
void *p);
#ifdef __cplusplus
}
#endif
#endif // CONFIG_RTAI_TRACE
#endif // __TRACE_H__

68
addons/cpp/watchdog.cc Normal file
View file

@ -0,0 +1,68 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: watchdog.cc,v 1.4 2013/10/22 14:54:15 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "watchdog.h"
namespace RTAI {
namespace Watchdog {
int set_grace(int new_value)
{
return rt_wdset_grace( new_value );
}
int set_gracediv(int new_value)
{
return rt_wdset_gracediv( new_value );
}
wd_policy set_policy(wd_policy new_value)
{
return rt_wdset_policy( new_value );
}
int set_slip(int new_value)
{
return rt_wdset_slip( new_value );
}
int set_stretch(int new_value)
{
return rt_wdset_stretch( new_value );
}
int set_limit(int new_value)
{
return rt_wdset_limit( new_value );
}
int set_safety(int new_value)
{
return rt_wdset_safety( new_value );
}
}; // namespace Watchdog
}; // namespace RTAI

57
addons/cpp/watchdog.h Normal file
View file

@ -0,0 +1,57 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: watchdog.h,v 1.4 2013/10/22 14:54:15 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __WATCHDOG_H__
#define __WATCHDOG_H__
#include "rtai.h"
#include "rtai_sched.h"
#include "time.h"
extern "C" {
#include "rtai_wd.h"
}
namespace RTAI {
/**
* Watchdog namesapce
*/
namespace Watchdog
{
int set_grace(int new_value);
int set_gracediv(int new_value);
wd_policy set_policy(wd_policy new_value);
int set_slip(int new_value);
int set_stretch(int new_value);
int set_limit(int new_value);
int set_safety(int new_value);
}; // namespace Watchdog
}; // namespace RTAI
#endif

View file

@ -0,0 +1,51 @@
/*
* Project: rtai_cpp - RTAI C++ Framework
*
* File: $Id: watchdog_init.c,v 1.4 2013/10/22 14:54:15 ando Exp $
*
* Copyright: (C) 2001,2002 Erwin Rol <erwin@muffin.org>
*
* Licence:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <rtai_malloc.h>
#include <rtai.h>
// RTAI-- MODULE INIT and CLEANUP functions
MODULE_LICENSE("GPL");
MODULE_AUTHOR("the RTAI-Team (contact person Erwin Rol)");
MODULE_DESCRIPTION("RTAI C++ Watchdog support");
int __init rtai_cpp_watchdog_init(void){
return 0;
}
void rtai_cpp_watchdog_cleanup(void)
{
}
module_init(rtai_cpp_watchdog_init)
module_exit(rtai_cpp_watchdog_cleanup)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,213 @@
/*
* Copyright (C) 2007 Jan Kiszka <jan.kiszka@web.de>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Manages the I/O access method of the driver. */
typedef enum { MODE_PIO, MODE_MMIO } io_mode_t;
#if defined(CONFIG_RTAI_16550A_PIO) || \
defined(CONFIG_RTAI_16550A_ANY)
static unsigned long io[MAX_DEVICES];
compat_module_param_array(io, ulong, MAX_DEVICES, 0400);
MODULE_PARM_DESC(io, "I/O port addresses of the serial devices");
#endif /* CONFIG_RTAI_16550A_PIO || CONFIG_RTAI_16550A_ANY */
#if defined(CONFIG_RTAI_16550A_MMIO) || \
defined(CONFIG_RTAI_16550A_ANY)
static unsigned long mem[MAX_DEVICES];
static void *mapped_io[MAX_DEVICES];
compat_module_param_array(mem, ulong, MAX_DEVICES, 0400);
MODULE_PARM_DESC(mem, "I/O memory addresses of the serial devices");
#endif /* CONFIG_RTAI_16550A_MMIO || CONFIG_RTAI_16550A_ANY */
#ifdef CONFIG_RTAI_16550A_PIO
#define RT_16550_IO_INLINE inline
extern void *mapped_io[]; /* dummy */
static inline unsigned long rt_16550_addr_param(int dev_id)
{
return io[dev_id];
}
static inline int rt_16550_addr_param_valid(int dev_id)
{
return 1;
}
static inline unsigned long rt_16550_base_addr(int dev_id)
{
return io[dev_id];
}
static inline io_mode_t rt_16550_io_mode(int dev_id)
{
return MODE_PIO;
}
static inline io_mode_t
rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
{
return MODE_PIO;
}
static inline void
rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
{
ctx->base_addr = io[dev_id];
}
#elif defined(CONFIG_RTAI_16550A_MMIO)
#define RT_16550_IO_INLINE inline
extern unsigned long io[]; /* dummy */
static inline unsigned long rt_16550_addr_param(int dev_id)
{
return mem[dev_id];
}
static inline int rt_16550_addr_param_valid(int dev_id)
{
return 1;
}
static inline unsigned long rt_16550_base_addr(int dev_id)
{
return (unsigned long)mapped_io[dev_id];
}
static inline io_mode_t rt_16550_io_mode(int dev_id)
{
return MODE_MMIO;
}
static inline io_mode_t
rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
{
return MODE_MMIO;
}
static inline void
rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
{
ctx->base_addr = (unsigned long)mapped_io[dev_id];
}
#elif defined(CONFIG_RTAI_16550A_ANY)
#define RT_16550_IO_INLINE /* uninline */
static inline unsigned long rt_16550_addr_param(int dev_id)
{
return (io[dev_id]) ? io[dev_id] : mem[dev_id];
}
static inline int rt_16550_addr_param_valid(int dev_id)
{
return !(io[dev_id] && mem[dev_id]);
}
static inline unsigned long rt_16550_base_addr(int dev_id)
{
return (io[dev_id]) ? io[dev_id] : (unsigned long)mapped_io[dev_id];
}
static inline io_mode_t rt_16550_io_mode(int dev_id)
{
return (io[dev_id]) ? MODE_PIO : MODE_MMIO;
}
static inline io_mode_t
rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
{
return ctx->io_mode;
}
static inline void
rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
{
if (io[dev_id]) {
ctx->base_addr = io[dev_id];
ctx->io_mode = MODE_PIO;
} else {
ctx->base_addr = (unsigned long)mapped_io[dev_id];
ctx->io_mode = MODE_MMIO;
}
}
#else
# error Unsupported I/O access method
#endif
static RT_16550_IO_INLINE u8
rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
{
switch (io_mode) {
case MODE_PIO:
return inb(base + off);
default: /* MODE_MMIO */
return readb((void *)base + off);
}
}
static RT_16550_IO_INLINE void
rt_16550_reg_out(io_mode_t io_mode, unsigned long base, int off, u8 val)
{
switch (io_mode) {
case MODE_PIO:
outb(val, base + off);
break;
case MODE_MMIO:
writeb(val, (void *)base + off);
break;
}
}
static int rt_16550_init_io(int dev_id, char* name)
{
switch (rt_16550_io_mode(dev_id)) {
case MODE_PIO:
if (!request_region(rt_16550_addr_param(dev_id), 8, name))
return -EBUSY;
break;
case MODE_MMIO:
mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), 8);
if (!mapped_io[dev_id])
return -EBUSY;
break;
}
return 0;
}
static void rt_16550_release_io(int dev_id)
{
switch (rt_16550_io_mode(dev_id)) {
case MODE_PIO:
release_region(io[dev_id], 8);
break;
case MODE_MMIO:
iounmap(mapped_io[dev_id]);
break;
}
}

View file

@ -0,0 +1,288 @@
/*
* Copyright (C) 2006-2007 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2011 Stefan Kisdaroczi <kisda@hispeed.ch>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* Rtai 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.
*
* Rtai 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 Rtai; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if defined(CONFIG_RTAI_DRIVERS_16550A_PCI)
#include <linux/pci.h>
struct rt_16550_pci_board {
char *name;
resource_size_t resource_base_addr;
unsigned int nports;
unsigned int port_ofs;
unsigned long irqtype;
unsigned int baud_base;
int tx_fifo;
};
#if defined(CONFIG_RTAI_DRIVERS_16550A_PCI_MOXA)
#define PCI_DEVICE_ID_CP112UL 0x1120
#define PCI_DEVICE_ID_CP114UL 0x1143
#define PCI_DEVICE_ID_CP138U 0x1380
static const struct rt_16550_pci_board rt_16550_moxa_c104 = {
.name = "Moxa C104H/PCI",
.resource_base_addr = 2,
.nports = 4,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_c168 = {
.name = "Moxa C168H/PCI",
.resource_base_addr = 2,
.nports = 8,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp114 = {
.name = "Moxa CP-114",
.resource_base_addr = 2,
.nports = 4,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp132 = {
.name = "Moxa CP-132",
.resource_base_addr = 2,
.nports = 2,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp102u = {
.name = "Moxa CP-102U",
.resource_base_addr = 2,
.nports = 2,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp102ul = {
.name = "Moxa CP-102UL",
.resource_base_addr = 2,
.nports = 2,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp104u = {
.name = "Moxa CP-104U",
.resource_base_addr = 2,
.nports = 4,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp112ul = {
.name = "Moxa CP-112UL",
.resource_base_addr = 2,
.nports = 2,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp114ul = {
.name = "Moxa CP-114UL",
.resource_base_addr = 2,
.nports = 4,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp118u = {
.name = "Moxa CP-118U",
.resource_base_addr = 2,
.nports = 8,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp132u = {
.name = "Moxa CP-132U",
.resource_base_addr = 2,
.nports = 2,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp134u = {
.name = "Moxa CP-134U",
.resource_base_addr = 2,
.nports = 4,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp138u = {
.name = "Moxa CP-138U",
.resource_base_addr = 2,
.nports = 8,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
static const struct rt_16550_pci_board rt_16550_moxa_cp168u = {
.name = "Moxa CP-168U",
.resource_base_addr = 2,
.nports = 8,
.port_ofs = 8,
.baud_base = 921600,
.tx_fifo = 16,
.irqtype = RTDM_IRQTYPE_SHARED,
};
#endif
DEFINE_PCI_DEVICE_TABLE( rt_16550_pci_table ) = {
#if defined(CONFIG_RTAI_DRIVERS_16550A_PCI_MOXA)
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104),
.driver_data = (unsigned long)&rt_16550_moxa_c104},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168),
.driver_data = (unsigned long)&rt_16550_moxa_c168},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114),
.driver_data = (unsigned long)&rt_16550_moxa_cp114},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132),
.driver_data = (unsigned long)&rt_16550_moxa_cp132},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U),
.driver_data = (unsigned long)&rt_16550_moxa_cp102u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
.driver_data = (unsigned long)&rt_16550_moxa_cp102ul},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U),
.driver_data = (unsigned long)&rt_16550_moxa_cp104u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL),
.driver_data = (unsigned long)&rt_16550_moxa_cp112ul},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL),
.driver_data = (unsigned long)&rt_16550_moxa_cp114ul},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U),
.driver_data = (unsigned long)&rt_16550_moxa_cp118u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U),
.driver_data = (unsigned long)&rt_16550_moxa_cp132u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U),
.driver_data = (unsigned long)&rt_16550_moxa_cp134u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U),
.driver_data = (unsigned long)&rt_16550_moxa_cp138u},
{PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U),
.driver_data = (unsigned long)&rt_16550_moxa_cp168u},
#endif
{ }
};
static int rt_16550_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct rt_16550_pci_board *board;
int err;
int i;
int port = 0;
int base_addr;
int max_devices = 0;
if (!ent->driver_data)
return -ENODEV;
board = (struct rt_16550_pci_board *)ent->driver_data;
for (i = 0; i < MAX_DEVICES; i++)
if (!rt_16550_addr_param(i))
max_devices++;
if (board->nports > max_devices)
return -ENODEV;
if ((err = pci_enable_device(pdev)))
return err;
base_addr = pci_resource_start(pdev, board->resource_base_addr);
for (i = 0; i < MAX_DEVICES; i++) {
if ((port < board->nports) && (!rt_16550_addr_param(i))) {
io[i] = base_addr + port * board->port_ofs;
irq[i] = pdev->irq;
irqtype[i] = board->irqtype;
baud_base[i] = board->baud_base;
tx_fifo[i] = board->tx_fifo;
port++;
}
}
return 0;
}
static void rt_16550_pci_remove(struct pci_dev *pdev) {
pci_disable_device( pdev );
};
static struct pci_driver rt_16550_pci_driver = {
.name = RT_16550_DRIVER_NAME,
.id_table = rt_16550_pci_table,
.probe = rt_16550_pci_probe,
.remove = rt_16550_pci_remove
};
static int pci_registered;
static inline void rt_16550_pci_init(void)
{
if (pci_register_driver(&rt_16550_pci_driver) == 0)
pci_registered = 1;
}
static inline void rt_16550_pci_cleanup(void)
{
if (pci_registered)
pci_unregister_driver(&rt_16550_pci_driver);
}
#else /* Linux < 2.6.0 || !CONFIG_PCI || !(..._16550A_PCI */
#define rt_16550_pci_init() do { } while (0)
#define rt_16550_pci_cleanup() do { } while (0)
#endif /* Linux < 2.6.0 || !CONFIG_PCI || !(..._16550A_PCI */

View file

@ -0,0 +1,389 @@
/*
* Copyright (C) 2006-2007 Jan Kiszka <jan.kiszka@web.de>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && defined(CONFIG_PNP) && \
(defined(CONFIG_RTAI_16550A_PIO) || \
defined(CONFIG_RTAI_16550A_ANY))
#include <linux/pnp.h>
#define UNKNOWN_DEV 0x3000
/* Bluntly cloned from drivers/serial/8250_pnp.c */
static const struct pnp_device_id rt_16550_pnp_tbl[] = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "AAC000F", 0 },
/* Anchor Datacomm BV */
/* SXPro 144 External Data Fax Modem Plug & Play */
{ "ADC0001", 0 },
/* SXPro 288 External Data Fax Modem Plug & Play */
{ "ADC0002", 0 },
/* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
{ "AEI0250", 0 },
/* Actiontec ISA PNP 56K X2 Fax Modem */
{ "AEI1240", 0 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ },
/* AZT3005 PnP SOUND DEVICE */
{ "AZT4001", 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */
{ "BDP3336", 0 },
/* Boca Research */
/* Boca Complete Ofc Communicator 14.4 Data-FAX */
{ "BRI0A49", 0 },
/* Boca Research 33,600 ACF Modem */
{ "BRI1400", 0 },
/* Boca 33.6 Kbps Internal FD34FSVD */
{ "BRI3400", 0 },
/* Boca 33.6 Kbps Internal FD34FSVD */
{ "BRI0A49", 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */
{ "BDP3336", 0 },
/* Computer Peripherals Inc */
/* EuroViVa CommCenter-33.6 SP PnP */
{ "CPI4050", 0 },
/* Creative Labs */
/* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
{ "CTL3001", 0 },
/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
{ "CTL3011", 0 },
/* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
{ "DMB1032", 0 },
/* Creative Modem Blaster V.90 DI5660 */
{ "DMB2001", 0 },
/* E-Tech */
/* E-Tech CyberBULLET PC56RVP */
{ "ETT0002", 0 },
/* FUJITSU */
/* Fujitsu 33600 PnP-I2 R Plug & Play */
{ "FUJ0202", 0 },
/* Fujitsu FMV-FX431 Plug & Play */
{ "FUJ0205", 0 },
/* Fujitsu 33600 PnP-I4 R Plug & Play */
{ "FUJ0206", 0 },
/* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
{ "FUJ0209", 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "GVC000F", 0 },
/* Hayes */
/* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
{ "HAY0001", 0 },
/* Hayes Optima 336 V.34 + FAX + Voice PnP */
{ "HAY000C", 0 },
/* Hayes Optima 336B V.34 + FAX + Voice PnP */
{ "HAY000D", 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5670", 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5674", 0 },
/* Hayes Accura 56K Fax Modem PnP */
{ "HAY5675", 0 },
/* Hayes 288, V.34 + FAX */
{ "HAYF000", 0 },
/* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
{ "HAYF001", 0 },
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
/* Intertex 33k6 56k Voice EXT PnP */
{ "IXDC901", 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDD801", 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDD901", 0 },
/* Intertex 28k8 33k6 Voice SP INT PnP */
{ "IXDF401", 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDF801", 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDF901", 0 },
/* Kortex International */
/* KORTEX 28800 Externe PnP */
{ "KOR4522", 0 },
/* KXPro 33.6 Vocal ASVD PnP */
{ "KORF661", 0 },
/* Lasat */
/* LASAT Internet 33600 PnP */
{ "LAS4040", 0 },
/* Lasat Safire 560 PnP */
{ "LAS4540", 0 },
/* Lasat Safire 336 PnP */
{ "LAS5440", 0 },
/* Microcom, Inc. */
/* Microcom TravelPorte FAST V.34 Plug & Play */
{ "MNP0281", 0 },
/* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
{ "MNP0336", 0 },
/* Microcom DeskPorte FAST EP 28.8 Plug & Play */
{ "MNP0339", 0 },
/* Microcom DeskPorte 28.8P Plug & Play */
{ "MNP0342", 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0500", 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0501", 0 },
/* Microcom DeskPorte 28.8S Internal Plug & Play */
{ "MNP0502", 0 },
/* Motorola */
/* Motorola BitSURFR Plug & Play */
{ "MOT1105", 0 },
/* Motorola TA210 Plug & Play */
{ "MOT1111", 0 },
/* Motorola HMTA 200 (ISDN) Plug & Play */
{ "MOT1114", 0 },
/* Motorola BitSURFR Plug & Play */
{ "MOT1115", 0 },
/* Motorola Lifestyle 28.8 Internal */
{ "MOT1190", 0 },
/* Motorola V.3400 Plug & Play */
{ "MOT1501", 0 },
/* Motorola Lifestyle 28.8 V.34 Plug & Play */
{ "MOT1502", 0 },
/* Motorola Power 28.8 V.34 Plug & Play */
{ "MOT1505", 0 },
/* Motorola ModemSURFR External 28.8 Plug & Play */
{ "MOT1509", 0 },
/* Motorola Premier 33.6 Desktop Plug & Play */
{ "MOT150A", 0 },
/* Motorola VoiceSURFR 56K External PnP */
{ "MOT150F", 0 },
/* Motorola ModemSURFR 56K External PnP */
{ "MOT1510", 0 },
/* Motorola ModemSURFR 56K Internal PnP */
{ "MOT1550", 0 },
/* Motorola ModemSURFR Internal 28.8 Plug & Play */
{ "MOT1560", 0 },
/* Motorola Premier 33.6 Internal Plug & Play */
{ "MOT1580", 0 },
/* Motorola OnlineSURFR 28.8 Internal Plug & Play */
{ "MOT15B0", 0 },
/* Motorola VoiceSURFR 56K Internal PnP */
{ "MOT15F0", 0 },
/* Com 1 */
/* Deskline K56 Phone System PnP */
{ "MVX00A1", 0 },
/* PC Rider K56 Phone System PnP */
{ "MVX00F2", 0 },
/* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
{ "nEC8241", 0 },
/* Pace 56 Voice Internal Plug & Play Modem */
{ "PMC2430", 0 },
/* Generic */
/* Generic standard PC COM port */
{ "PNP0500", 0 },
/* Generic 16550A-compatible COM port */
{ "PNP0501", 0 },
/* Compaq 14400 Modem */
{ "PNPC000", 0 },
/* Compaq 2400/9600 Modem */
{ "PNPC001", 0 },
/* Dial-Up Networking Serial Cable between 2 PCs */
{ "PNPC031", 0 },
/* Dial-Up Networking Parallel Cable between 2 PCs */
{ "PNPC032", 0 },
/* Standard 9600 bps Modem */
{ "PNPC100", 0 },
/* Standard 14400 bps Modem */
{ "PNPC101", 0 },
/* Standard 28800 bps Modem*/
{ "PNPC102", 0 },
/* Standard Modem*/
{ "PNPC103", 0 },
/* Standard 9600 bps Modem*/
{ "PNPC104", 0 },
/* Standard 14400 bps Modem*/
{ "PNPC105", 0 },
/* Standard 28800 bps Modem*/
{ "PNPC106", 0 },
/* Standard Modem */
{ "PNPC107", 0 },
/* Standard 9600 bps Modem */
{ "PNPC108", 0 },
/* Standard 14400 bps Modem */
{ "PNPC109", 0 },
/* Standard 28800 bps Modem */
{ "PNPC10A", 0 },
/* Standard Modem */
{ "PNPC10B", 0 },
/* Standard 9600 bps Modem */
{ "PNPC10C", 0 },
/* Standard 14400 bps Modem */
{ "PNPC10D", 0 },
/* Standard 28800 bps Modem */
{ "PNPC10E", 0 },
/* Standard Modem */
{ "PNPC10F", 0 },
/* Standard PCMCIA Card Modem */
{ "PNP2000", 0 },
/* Rockwell */
/* Modular Technology */
/* Rockwell 33.6 DPF Internal PnP */
/* Modular Technology 33.6 Internal PnP */
{ "ROK0030", 0 },
/* Kortex International */
/* KORTEX 14400 Externe PnP */
{ "ROK0100", 0 },
/* Rockwell 28.8 */
{ "ROK4120", 0 },
/* Viking Components, Inc */
/* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
{ "ROK4920", 0 },
/* Rockwell */
/* British Telecom */
/* Modular Technology */
/* Rockwell 33.6 DPF External PnP */
/* BT Prologue 33.6 External PnP */
/* Modular Technology 33.6 External PnP */
{ "RSS00A0", 0 },
/* Viking 56K FAX INT */
{ "RSS0262", 0 },
/* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
{ "RSS0250", 0 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ "SUP1310", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1421", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1590", 0 },
/* SupraExpress 336i Sp ASVD */
{ "SUP1620", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1760", 0 },
/* SupraExpress 56i Sp Intl */
{ "SUP2171", 0 },
/* Phoebe Micro */
/* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
{ "TEX0011", 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "UAC000F", 0 },
/* 3Com Corp. */
/* Gateway Telepath IIvi 33.6 */
{ "USR0000", 0 },
/* U.S. Robotics Sporster 33.6K Fax INT PnP */
{ "USR0002", 0 },
/* Sportster Vi 14.4 PnP FAX Voicemail */
{ "USR0004", 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR0006", 0 },
/* U.S. Robotics 33.6K Voice EXT PnP */
{ "USR0007", 0 },
/* U.S. Robotics Courier V.Everything INT PnP */
{ "USR0009", 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR2002", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR2070", 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR2080", 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3031", 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3050", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3070", 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR3080", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3090", 0 },
/* U.S. Robotics 56K Message */
{ "USR9100", 0 },
/* U.S. Robotics 56K FAX EXT PnP*/
{ "USR9160", 0 },
/* U.S. Robotics 56K FAX INT PnP*/
{ "USR9170", 0 },
/* U.S. Robotics 56K Voice EXT PnP*/
{ "USR9180", 0 },
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
/* Wacom tablets */
{ "WACF004", 0 },
{ "WACF005", 0 },
{ "WACF006", 0 },
/* Compaq touchscreen */
{ "FPI2002", 0 },
/* Fujitsu Stylistic touchscreens */
{ "FUJ02B2", 0 },
{ "FUJ02B3", 0 },
/* Fujitsu Stylistic LT touchscreens */
{ "FUJ02B4", 0 },
/* Passive Fujitsu Stylistic touchscreens */
{ "FUJ02B6", 0 },
{ "FUJ02B7", 0 },
{ "FUJ02B8", 0 },
{ "FUJ02B9", 0 },
{ "FUJ02BC", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
{ "PNPCXXX", UNKNOWN_DEV },
/* More unkown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
{ "", 0 }
};
static int rt_16550_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
int i;
for (i = 0; i < MAX_DEVICES; i++)
if (pnp_port_valid(dev, 0) &&
pnp_port_start(dev, 0) == io[i]) {
if (!irq[i])
irq[i] = pnp_irq(dev, 0);
return 0;
}
return -ENODEV;
}
static struct pnp_driver rt_16550_pnp_driver = {
.name = RT_16550_DRIVER_NAME,
.id_table = rt_16550_pnp_tbl,
.probe = rt_16550_pnp_probe,
};
static int pnp_registered;
static inline void rt_16550_pnp_init(void)
{
if (pnp_register_driver(&rt_16550_pnp_driver) == 0)
pnp_registered = 1;
}
static inline void rt_16550_pnp_cleanup(void)
{
if (pnp_registered)
pnp_unregister_driver(&rt_16550_pnp_driver);
}
#else /* Linux < 2.6.0 || !CONFIG_PNP || !(..._16550A_IO || ..._16550A_ANY) */
#define rt_16550_pnp_init() do { } while (0)
#define rt_16550_pnp_cleanup() do { } while (0)
#endif /* Linux < 2.6.0 || !CONFIG_PNP || !(..._16550A_IO || ..._16550A_ANY) */

View file

@ -0,0 +1,57 @@
moduledir = @RTAI_MODULE_DIR@
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
lib16550A_a_SOURCES = 16550A.c
distfiles = $(lib16550A_a_SOURCES)
if CONFIG_KBUILD
rtai_16550A$(modext): @RTAI_KBUILD_ENV@
rtai_16550A$(modext): $(lib16550A_a_SOURCES) FORCE
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ rtai_extradef="@RTAI_KMOD_CFLAGS@" \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
rm -f FORCE
distclean-local:
@RTAI_KBUILD_DISTCLEAN@
else
noinst_LIBRARIES = lib16550A.a
lib16550A_a_AR = $(CROSS_COMPILE)ar cru
INCLUDES = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I$(top_srcdir)/addons \
-I$(top_srcdir)/addons/drivers/16550A/ \
-I../../../base/include \
-I../..
rtai_16550A.o: lib16550A.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: rtai_16550A$(modext)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: rtai_16550A$(modext)
$(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $< $(DESTDIR)$(moduledir)
uninstall-local:
$(RM) $(DESTDIR)$(moduledir)/rtai_16550A$(modext)
.PHONY: FORCE
EXTRA_DIST = $(distfiles) Makefile.kbuild \
16550A_io.h 16550A_pci.h 16550A_pnp.h

View file

@ -0,0 +1,10 @@
EXTRA_CFLAGS += -I$(rtai_srctree)/base/include \
-I$(rtai_srctree)/addons/drivers/16550A \
-I$(rtai_srcdir)/../.. \
-I$(src)/../../../base/include \
-I$(src)/../../.. \
$(rtai_extradef)
obj-m += $(rtai_target).o
$(rtai_target)-objs := $(rtai_objs)

View file

@ -0,0 +1,11 @@
OPTDIRS =
if CONFIG_RTAI_DRIVERS_SERIAL
OPTDIRS += serial
endif
if CONFIG_RTAI_DRIVERS_16550A
OPTDIRS += 16550A
endif
SUBDIRS = $(OPTDIRS)

View file

@ -0,0 +1,46 @@
moduledir = @RTAI_MODULE_DIR@
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
libserial_a_SOURCES = \
serial.c \
serialP.h
include_HEADERS = rtai_serial.h
if CONFIG_KBUILD
rtai_serial.ko: @RTAI_KBUILD_ENV@
rtai_serial.ko: $(libserial_a_SOURCES)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
else
noinst_LIBRARIES = libserial.a
libserial_a_AR = $(CROSS_COMPILE)ar cru
INCLUDES = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../../base/include
rtai_serial.o: libserial.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: rtai_serial$(modext)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: rtai_serial$(modext)
$(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $< $(DESTDIR)$(moduledir)
EXTRA_DIST = Makefile.kbuild

View file

@ -0,0 +1,9 @@
EXTRA_CFLAGS += -I$(rtai_srctree)/base/include \
-I$(rtai_srcdir) \
-I$(src)/../../../base/include \
-I$(src)/../../.. \
-D__IN_RTAI__
obj-m += rtai_serial.o
rtai_serial-objs := $(rtai_objs)

View file

@ -0,0 +1,433 @@
This is a complete rewriting of rt_com. Changes:
- possibility of parametrizing the base_adr and irq of the serial ports used,
along with rx/tx buffer sizes, at insmod,
- new read/write buffer management, with the possibility of previewing what's
in the receiver before reading,
- enhanced interrupt service management,
- interrupt callback function with user thresholded callbacks,
- special interrupt callback function for serial port hardware errors,
- the above callbacks are available in user space also,
- info functions to check rx/tx data availability,
Compatibility with rt_com is provided through inlines and defines.
rt_com_hwsetup is not supported, use the appropriate parametrization at insmod.
Any comment is welcomed.
The work of all the original rt_com writers: Jens Michaelsen, Jochen Kupper,
Hua Mao, Roberto Finazzi, provided the base for an easy rewriting and is warmly
acknowledged.
********************************************************************************
N.B.: in the followings "spct" stands for "serial port control table".
********************************************************************************
+------------------------------------------------------------------------------+
int rt_spclear_rx(unsigned int tty)
+------------------------------------------------------------------------------+
Clear serial port rx and reset the related buffer and UART rx FIFO.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spclear_tx(unsigned int tty)
+------------------------------------------------------------------------------+
Clear serial port tx and reset the related buffer.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spset_mode(unsigned int tty, int mode)
+------------------------------------------------------------------------------+
Set serial port flow control.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
mode working mode, i.e. handshaking and the likes, see
available modes and related macros in rtai_spdrv :
RT_SP_NO_HAND_SHAKE no hw flow control
RT_SP_DSR_ON_TX transmitter enabled if DSR active
RT_SP_HW_FLOW RTS-CTS flow control
Note that RT_SP_DSR_ON_TX and RT_SP_HW_FLOW can be
ORed toghether.
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spset_fifotrig(unsigned int tty, int fifotrig)
+------------------------------------------------------------------------------+
Set serial port UART receiver fifo trigger level.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
fifotrig this value must be choosen between one of these
valued defined in rt_spdrv.h :
RT_SP_FIFO_DISABLE
RT_SP_FIFO_SIZE_1
RT_SP_FIFO_SIZE_4
RT_SP_FIFO_SIZE_8
RT_SP_FIFO_SIZE_14
RT_SP_FIFO_SIZE_DEFAULT
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spset_mcr(unsigned int tty, int mask, int setbits)
+------------------------------------------------------------------------------+
Set MODEM Control Register (MCR). Can be used to set the status
of DTR and RTS lines.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
mask Output mask:
RT_COM_DTR, RT_COM_RTS or any ORed combination.
setbits 0 -> reset bits in mask
!= 0 -> set bits in mask
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
-EINVAL wrong mask value
+------------------------------------------------------------------------------+
int rt_spget_msr(unsigned int tty, int mask)
+------------------------------------------------------------------------------+
Get serial port MODEM Status Register (MSR) (CTS, DSR, RI, DCD).
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
mask Input mask:
RT_SP_CTS, RT_SP_DSR, RT_SP_RI, RT_SP_DCD
or any ORed combination.
return:
>= 0 input signal status, i.e. the bitwise-OR of
the signal argument and MSR register.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spget_err(unsigned int tty)
+------------------------------------------------------------------------------+
Return the last error detected on a serial port.
param:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
>=0 tipically one or more codes ORed :
RT_SP_BUFFER_FULL rx buffer full
RT_SP_BUFFER_OVF rx buffer overflow (chars missed)
RT_SP_OVERRUN_ERR rx overrun (chars missed)
RT_SP_PARITY_ERR parity error
RT_SP_FRAMING_ERR framing error
RT_SP_BREAK break condition
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spwrite(unsigned int tty, char *msg, int msg_size)
+------------------------------------------------------------------------------+
Write to a serial port.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
msg pointer to buffer of char to send.
msg_size abs(msg_size) is the number of bytes to write.
If > 0, write bytes that are possible to send.
If < 0, write bytes only if possible to write them all
together.
return:
>= 0 number of bytes not written.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spread(unsigned int tty, char *msg, int msg_size)
+------------------------------------------------------------------------------+
Read from a serial port.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
msg Address of data buffer. Needs to be of size > cnt !
msg_size abs(msg_size) is the number of bytes to read.
If > 0, read all the bytes up to msg_size
If < 0, read bytes only if it is possible to read them all
together.
return:
>= 0 number of bytes not read.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spevdrp(unsigned int tty, char *msg, int msg_size)
+------------------------------------------------------------------------------+
Eavesdrop data we got from a line just for a preview, i.e. keeping the read
buffer unchanged.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
msg Address of data buffer. Needs to be of size > cnt !
msg_size abs(msg_size) is the number of bytes to read.
If > 0, read all the bytes up to msg_size
If < 0, read bytes only if it is possible to read them all
together.
return:
>= 0 number of bytes not eavesdropped.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spget_rxavbs(unsigned int tty)
+------------------------------------------------------------------------------+
Get the number of bytes available in rx buffer.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
>= 0 number of readable bytes.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spget_txfrbs(unsigned int tty)
+------------------------------------------------------------------------------+
Get the number of free bytes in rx buffer.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
>= 0 number of writable bytes.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spset_thrs(int tty, int rxthrs, int txthrs)
+------------------------------------------------------------------------------+
Set rx and tx thresholds for callback function.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
rxthrs call callback fun when rx has available a number of bytes
>= rxthrs.
txthrs call callback fun when tx has a free a number of bytes
>= txthrs.
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spset_callback_fun(int tty, void (*callback_fun)(int, int),
int rxthrs, int txthrs)
+------------------------------------------------------------------------------+
Define the callback function to be called when the chars in the receive
buffer or the free chars in the transmit buffer have reached the
specified thresholds
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
callback_fun user assigned callback function, it will be called when
the received/trasmitted bytes give/live the related
buffers with a number of bytes >= the corresponding
threshold values, passing the bytes available/free in
the buffers.
return:
>= 0 address of any already existing calbackfun, cast to int,
-ENODEV no entry in spct slots for that device.
-EINVAL if wrong parameter value
+------------------------------------------------------------------------------+
int rt_spset_err_callback_fun(int tty, void (*err_callback_fun)(int))
+------------------------------------------------------------------------------+
Define the callback function to be called when the interrupt service routine
detect an error
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
err_callback_fun user assigned callback function, it will be called
when an error (the same reported by rt_spget_err) is
detected by the interrupt service routine.
return:
>= 0 address of any already existing calbackfun, cast to int,
-ENODEV no entry in spct slots for that device.
-EINVAL if wrong parameter value
+------------------------------------------------------------------------------+
int rt_spopen(unsigned int tty, unsigned int baud, unsigned int numbits,
unsigned int stopbits, unsigned int parity, int mode,
int fifotrig)
+------------------------------------------------------------------------------+
Setup and open a serial port.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
baud Data transmission rate to use [Byte/s]: 50 .. 115200.
numbits number of bits per char
5,6,7,8
stopbits Number of stopbits to use.
1 gives you one stopbit,
2 actually gives really two stopbits for character lengths
of 6,7,8 bit, but 1.5 stopbits for a character length of
5 bits.
parity Parity for transmission protocol.
Is possible to choose between macros defined in rt_spdrv.h :
RT_SP_PARITY_NONE
RT_SP_PARITY_EVEN
RT_SP_PARITY_ODD
RT_SP_PARITY_HIGH
RT_SP_PARITY_LOW
mode working mode, i.e. handshaking and the likes, see
available modes and related macros in rtai_spdrv :
RT_SP_NO_HAND_SHAKE no hw flow control
RT_SP_DSR_ON_TX transmitter enabled if DSR active
RT_SP_HW_FLOW RTS-CTS flow control
Note that RT_SP_DSR_ON_TX and RT_SP_HW_FLOW can be
ORed toghether.
fifotrig this value must be choosen between one of these
valued defined in rt_spdrv.h :
RT_SP_FIFO_DISABLE
RT_SP_FIFO_SIZE_1
RT_SP_FIFO_SIZE_4
RT_SP_FIFO_SIZE_8
RT_SP_FIFO_SIZE_14
RT_SP_FIFO_SIZE_DEFAULT
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
-EINVAL if wrong parameter value
-EADDRINUSE if trying to open an openend port
+------------------------------------------------------------------------------+
int rt_spclose(unsigned int tty)
+------------------------------------------------------------------------------+
Close a serial port.
params:
tty Number corresponding to internal port numbering scheme,
i.e. the index of the spct slot to use.
return:
0 if all right.
-ENODEV no entry in spct slots for that device.
+------------------------------------------------------------------------------+
int rt_spwrite_timed(unsigned int tty, char *msg, int msg_size, RTIME delay)
+------------------------------------------------------------------------------+
Send one or more bytes with timeout
Arguments:
tty serial port number.
msg pointer to the chars to send.
msg_size number of bytes to send.
delay timeout in internal count unit,
use DELAY_FOREVER for a blocking send.
Return Value:
-ENODEV, if wrong tty number;
msg_size, if < 0 or another writer is already using tty;
one of the semaphores error messages;
0, message sent succesfully.
+------------------------------------------------------------------------------+
int rt_spread_timed(unsigned int tty, char *msg, int msg_size, RTIME delay)
+------------------------------------------------------------------------------+
Receive one or more bytes with timeout
Arguments:
tty serial port number.
msg pointer to the chars to receive.
msg_size the number of bytes to receive.
delay timeout in internal count unit,
use DELAY_FOREVER for a blocking receive.
Return Value:
-ENODEV, if wrong tty number;
msg_size, if < 0 or another reader is already using tty;
one of the semaphores error messages;
0, message received succesfully.
********************************************************************************
Paolo Mantegazza & Giuseppe Renoldi.

View file

@ -0,0 +1,418 @@
/*
* Copyright (C) 2002,2003 Paolo Mantegazza <mantegazza@aero.polimi.it>
* Giuseppe Renoldi <giuseppe@renoldi.org>
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTAI_SERIAL_H
#define _RTAI_SERIAL_H
#define TTY0 0
#define TTY1 1
#define COM1 TTY0
#define COM2 TTY1
#define RT_SP_NO_HAND_SHAKE 0x00
#define RT_SP_DSR_ON_TX 0x01
#define RT_SP_HW_FLOW 0x02
#define RT_SP_PARITY_EVEN 0x18
#define RT_SP_PARITY_NONE 0x00
#define RT_SP_PARITY_ODD 0x08
#define RT_SP_PARITY_HIGH 0x28
#define RT_SP_PARITY_LOW 0x38
#define RT_SP_FIFO_DISABLE 0x00
#define RT_SP_FIFO_SIZE_1 0x00
#define RT_SP_FIFO_SIZE_4 0x40
#define RT_SP_FIFO_SIZE_8 0x80
#define RT_SP_FIFO_SIZE_14 0xC0
#define RT_SP_FIFO_SIZE_DEFAULT RT_SP_FIFO_SIZE_8
#define RT_SP_DTR 0x01
#define RT_SP_RTS 0x02
#define RT_SP_CTS 0x10
#define RT_SP_DSR 0x20
#define RT_SP_RI 0x40
#define RT_SP_DCD 0x80
#define RT_SP_BUFFER_FULL 0x01
#define RT_SP_OVERRUN_ERR 0x02
#define RT_SP_PARITY_ERR 0x04
#define RT_SP_FRAMING_ERR 0x08
#define RT_SP_BREAK 0x10
#define RT_SP_BUFFER_OVF 0x20
#define DELAY_FOREVER 0x3FFFFFFFFFFFFFFFLL
#define FUN_EXT_RTAI_SP 14
#define _SPOPEN 0
#define _SPCLOSE 1
#define _SPREAD 2
#define _SPEVDRP 3
#define _SPWRITE 4
#define _SPCLEAR_RX 5
#define _SPCLEAR_TX 6
#define _SPGET_MSR 7
#define _SPSET_MCR 8
#define _SPGET_ERR 9
#define _SPSET_MODE 10
#define _SPSET_FIFOTRIG 11
#define _SPGET_RXAVBS 12
#define _SPGET_TXFRBS 13
#define _SPSET_THRS 14
#define _SPSET_CALLBACK 15
#define _SPSET_ERR_CALLBACK 16
#define _SPWAIT_USR_CALLBACK 17
#define _SPREAD_TIMED 18
#define _SPWRITE_TIMED 19
#ifdef __KERNEL__
#include <rtai.h>
RTAI_SYSCALL_MODE int rt_spopen(unsigned int tty, unsigned int baud, unsigned int numbits, unsigned int stopbits, unsigned int parity, int mode, int fifotrig);
RTAI_SYSCALL_MODE int rt_spclose(unsigned int tty);
RTAI_SYSCALL_MODE int rt_spread(unsigned int tty, char *msg, int msg_size);
RTAI_SYSCALL_MODE int rt_spevdrp(unsigned int tty, char *msg, int msg_size);
RTAI_SYSCALL_MODE int rt_spwrite(unsigned int tty, char *msg, int msg_size);
RTAI_SYSCALL_MODE int rt_spget_rxavbs(unsigned int tty);
RTAI_SYSCALL_MODE int rt_spget_txfrbs(unsigned int tty);
RTAI_SYSCALL_MODE int rt_spclear_rx(unsigned int tty);
RTAI_SYSCALL_MODE int rt_spclear_tx(unsigned int tty);
RTAI_SYSCALL_MODE int rt_spset_mcr(unsigned int tty, int mask, int setbits);
RTAI_SYSCALL_MODE int rt_spget_msr(unsigned int tty, int mask);
RTAI_SYSCALL_MODE int rt_spset_mode(unsigned int tty, int mode);
RTAI_SYSCALL_MODE int rt_spset_fifotrig(unsigned int tty, int fifotrig);
RTAI_SYSCALL_MODE int rt_spget_err(unsigned int tty);
long rt_spset_callback_fun(unsigned int tty, void (*callback_fun)(int, int), int rxthrs, int txthrs);
RTAI_SYSCALL_MODE int rt_spset_thrs(unsigned int tty, int rxthrs, int txthrs);
long rt_spset_err_callback_fun(unsigned int tty, void (*err_callback_fun)(int));
RTAI_SYSCALL_MODE int rt_spset_callback_fun_usr(unsigned int tty, unsigned long callback_fun, int rxthrs, int txthrs, int code, void *task);
RTAI_SYSCALL_MODE int rt_spset_err_callback_fun_usr(unsigned int tty, unsigned long err_callback_fun, int dummy1, int dummy2, int code, void *task);
RTAI_SYSCALL_MODE void rt_spwait_usr_callback(unsigned int tty, unsigned long *retvals);
RTAI_SYSCALL_MODE int rt_spread_timed(unsigned int tty, char *msg, int msg_size, RTIME delay);
RTAI_SYSCALL_MODE int rt_spwrite_timed(unsigned int tty, char *msg, int msg_size, RTIME delay);
/*
* rt_com compatibility functions.
*/
static inline int rt_com_setup(unsigned int tty,
int baud, int mode,
unsigned int parity,
unsigned int stopbits,
unsigned int numbits,
int fifotrig)
{
return baud <= 0 ? rt_spclose(tty) : rt_spopen(tty, baud, numbits, stopbits, parity, mode, fifotrig);
}
static inline int rt_com_read(unsigned int tty,
char *msg,
int msg_size)
{
int notrd;
if ((notrd = rt_spread(tty, msg, msg_size)) >= 0) {
return msg_size - notrd;
}
return notrd;
}
static inline int rt_com_write(unsigned int tty,
char *msg,
int msg_size)
{
int notwr;
if ((notwr = rt_spwrite(tty, msg, msg_size)) >= 0) {
return msg_size - notwr;
}
return notwr;
}
#define rt_com_clear_input(indx) rt_spclear_rx(indx)
#define rt_com_clear_output(indx) rt_spclear_tx(indx)
#define rt_com_write_modem(indx, mask, op) rt_spset_mcr(indx, mask, op)
#define rt_com_read_modem(indx, mask) rt_spget_msr(indx, mask)
#define rt_com_set_mode(indx, mode) rt_spset_mode(indx, mode)
#define rt_com_set_fifotrig(indx, fifotrig) rt_spset_fifotrig(indx, fifotrig)
#define rt_com_error(indx) rt_spget_err(indx)
#else /* !__KERNEL__ */
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <rtai_lxrt.h>
RTAI_PROTO(int, rt_spopen, (unsigned int tty, unsigned int baud, unsigned int numbits, unsigned int stopbits, unsigned int parity, int mode, int fifotrig))
{
struct { unsigned long tty, baud, numbits, stopbits, parity; long mode, fifotrig; } arg = { tty, baud, numbits, stopbits, parity, mode, fifotrig };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPOPEN, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spclose, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPCLOSE, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spread, (unsigned int tty, char *msg, int msg_size))
{
int notrd, size;
char lmsg[size = abs(msg_size)];
struct { unsigned long tty; char *msg; long msg_size; } arg = { tty, lmsg, msg_size };
notrd = rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPREAD, &arg).i[LOW];
if (notrd >= 0 && notrd != size) {
memcpy(msg, lmsg, size - notrd);
}
return notrd;
}
RTAI_PROTO(int, rt_spevdrp, (unsigned int tty, char *msg, int msg_size))
{
int notrd, size;
char lmsg[size = abs(msg_size)];
struct { unsigned long tty; char *msg; long msg_size; } arg = { tty, lmsg, msg_size };
notrd = rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPEVDRP, &arg).i[LOW];
if ( notrd >= 0 && notrd != size ) {
memcpy(msg, lmsg, size - notrd);
}
return notrd;
}
RTAI_PROTO(int, rt_spwrite, (unsigned int tty, char *msg, int msg_size))
{
int size;
char lmsg[size = abs(msg_size)];
struct { unsigned long tty; char *msg; long msg_size; } arg = { tty, lmsg, msg_size };
memcpy(lmsg, msg, size);
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPWRITE, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spread_timed, (unsigned int tty, char *msg, int msg_size, RTIME delay))
{
struct { unsigned long tty; char *msg; long msg_size; RTIME delay; } arg = { tty, msg, msg_size, delay };
return msg_size > 0 ? rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPREAD_TIMED, &arg).i[LOW] : msg_size;
}
RTAI_PROTO(int, rt_spwrite_timed, (unsigned int tty, char *msg, int msg_size, RTIME delay))
{
struct { unsigned long tty; char *msg; long msg_size; RTIME delay; } arg = { tty, msg, msg_size, delay };
return msg_size > 0 ? rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPWRITE_TIMED, &arg).i[LOW] : msg_size;
}
RTAI_PROTO(int, rt_spclear_rx, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPCLEAR_RX, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spclear_tx, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPCLEAR_TX, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spget_msr, (unsigned int tty, int mask))
{
struct { unsigned long tty; long mask; } arg = { tty, mask };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPGET_MSR, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spset_mcr, (unsigned int tty, int mask, int setbits))
{
struct { unsigned long tty; long mask, setbits; } arg = { tty, mask, setbits };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_MCR, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spget_err, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPGET_ERR, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spset_mode, (unsigned int tty, int mode))
{
struct { unsigned long tty; long mode; } arg = { tty, mode };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_MODE, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spset_fifotrig, (unsigned int tty, int fifotrig))
{
struct { unsigned long tty; long fifotrig; } arg = { tty, fifotrig };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_FIFOTRIG, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spget_rxavbs, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPGET_RXAVBS, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spget_txfrbs, (unsigned int tty))
{
struct { unsigned long tty; } arg = { tty };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPGET_TXFRBS, &arg).i[LOW];
}
RTAI_PROTO(int, rt_spset_thrs, (unsigned int tty, int rxthrs, int txthrs))
{
struct { unsigned long tty; long rxthrs, txthrs; } arg = { tty, rxthrs, txthrs };
return rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_THRS, &arg).i[LOW];
}
RTAI_PROTO(void, rt_spwait_usr_callback, (unsigned int tty, unsigned long *retvals))
{
struct { unsigned long tty; unsigned long *retvals; long size; } arg = { tty, retvals, 6*sizeof(unsigned long) };
rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPWAIT_USR_CALLBACK, &arg);
return;
}
#ifndef __CALLBACK_THREAD__
#define __CALLBACK_THREAD__
static void *callback_thread(void *farg)
{
unsigned long retvals[6];
struct farg_t { long tty; void *callback_fun; long rxthrs, txthrs, code; RT_TASK *task; } *arg;
arg = (struct farg_t *)farg;
if (!(arg->task = rt_task_init_schmod((unsigned long)arg, 0, 0, 0, SCHED_FIFO, 0xF))) {
printf("CANNOT INIT USER SPACE CALLBACK SUPPORT\n");
return (void *)1;
}
retvals[0] = arg->code;
arg->code = 0;
if (rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, retvals[0], arg).i[LOW] < 0) {
printf("CANNOT SET USER SPACE CALLBACK SUPPORT\n");
rt_task_delete(arg->task);
free(arg);
return (void *)1;
}
mlockall(MCL_CURRENT | MCL_FUTURE);
rt_make_hard_real_time();
while(1) {
rt_spwait_usr_callback(arg->tty, retvals);
if (!retvals[5]) break;
if (retvals[0]) {
((void(*)(unsigned long, unsigned long))retvals[0])(retvals[2], retvals[3]);
}
if (retvals[1]) {
((void(*)(unsigned long))retvals[1])(retvals[4]);
}
}
rt_make_soft_real_time();
rt_task_delete(arg->task);
free(arg);
return (void *)0;
}
#endif
RTAI_PROTO(int, rt_spset_callback_fun, (unsigned int tty, void (*callback_fun)(int, int), int rxthrs, int txthrs))
{
int ret;
pthread_t thread;
struct { long tty; void (*callback_fun)(int, int); long rxthrs, txthrs, code; void *task; } arg = { tty, callback_fun, rxthrs, txthrs, _SPSET_CALLBACK, 0 };
if ((ret = rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_CALLBACK, &arg).i[LOW]) == EINVAL) {
void *argp;
argp = (void *)malloc(sizeof(arg));
memcpy(argp, &arg, sizeof(arg));
return pthread_create(&thread, NULL, callback_thread, argp);
}
return ret;
}
RTAI_PROTO(int, rt_spset_err_callback_fun, (unsigned int tty, void (*err_callback_fun)(int)))
{
int ret;
pthread_t thread;
struct { long tty; void (*err_callback_fun)(int); long dummy1, dummy2, code; void *task; } arg = { tty, err_callback_fun, 0, 0, _SPSET_ERR_CALLBACK, 0 };
if ((ret = rtai_lxrt(FUN_EXT_RTAI_SP, SIZARG, _SPSET_ERR_CALLBACK, &arg).i[LOW]) == EINVAL) {
void *argp;
argp = (void *)malloc(sizeof(arg));
memcpy(argp, &arg, sizeof(arg));
return pthread_create(&thread, NULL, callback_thread, argp);
}
return ret;
}
static inline int rt_com_setup(unsigned int tty, int baud, int mode, unsigned int parity, unsigned int stopbits, unsigned int numbits, int fifotrig)
{
return baud <= 0 ? rt_spclose(tty) : rt_spopen(tty, baud, numbits, stopbits, parity, mode, fifotrig);
}
static inline int rt_com_read(unsigned int tty, char *msg, int msg_size)
{
int notrd;
if ((notrd = rt_spread(tty, msg, msg_size)) >= 0) {
return abs(msg_size) - notrd;
}
return notrd;
}
static inline int rt_com_write(unsigned int tty, char *msg, int msg_size)
{
int notwr;
if ((notwr = rt_spwrite(tty, msg, msg_size)) >= 0) {
return abs(msg_size) - notwr;
}
return notwr;
}
#define rt_com_clear_input(indx) rt_spclear_rx(indx)
#define rt_com_clear_output(indx) rt_spclear_tx(indx)
#define rt_com_write_modem(indx, mask, op) rt_spset_mcr(indx, mask, op)
#define rt_com_read_modem(indx, mask) rt_spget_msr(indx, mask)
#define rt_com_set_mode(indx, mode) rt_spset_mode(indx, mode)
#define rt_com_set_fifotrig(indx, fifotrig) rt_spset_fifotrig(indx, fifotrig)
#define rt_com_error(indx) rt_spget_err(indx)
#endif /* __KERNEL__ */
#endif /* !_RTAI_SERIAL_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,118 @@
/*
COPYRIGHT (C) 2002-2008 Paolo Mantegazza (mantegazza@aero.polimi.it)
Giuseppe Renoldi (giuseppe@renoldi.org)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef RTAI_SPDRV_HW_H
#define RTAI_SPDRV_HW_H
#define RTAI_SPDRV_NAME "RTAI_SPDRV"
#define CONFIG_SIZE 40 // likely abundant, twice the max # of serial ports
#define SPBUFSIZ 512 // bufsize will be (1 << SPBUFMSB)
#define RT_SP_CONFIG_INIT { 0x3f8, 4, 0x2f8, 3, }
#ifdef CONFIG_SMP
static DEFINE_SPINLOCK(splock);
#define chip_atomic_bgn(flags) do { rtai_hw_save_flags_and_cli(flags); rt_spin_lock(&splock); } while (0)
#define chip_atomic_end(flags) do { rt_spin_unlock(&splock); rtai_hw_restore_flags(flags); } while (0)
#define buf_atomic_bgn(flags, mbx) do { flags = rt_spin_lock_irqsave(&(mbx)->lock); } while (0)
#define buf_atomic_end(flags, mbx) do { rt_spin_unlock_irqrestore(flags, &(mbx)->lock); } while (0)
#else
#define chip_atomic_bgn(flags) do { rtai_hw_save_flags_and_cli(flags); } while (0)
#define chip_atomic_end(flags) do { rtai_hw_restore_flags(flags); } while (0)
#define buf_atomic_bgn(flags, mbx) do { rtai_save_flags_and_cli(flags); } while (0)
#define buf_atomic_end(flags, mbx) do { rtai_restore_flags(flags); } while (0)
#endif
#define ENABLE_SP(irq) rt_enable_irq(irq)
#define RT_SP_BASE_BAUD 115200
#define RT_SP_RXB 0x00
#define RT_SP_TXB 0x00
#define RT_SP_IER 0x01
#define RT_SP_IIR 0x02
#define RT_SP_FCR 0x02
#define RT_SP_LCR 0x03
#define RT_SP_MCR 0x04
#define RT_SP_LSR 0x05
#define RT_SP_MSR 0x06
#define RT_SP_DLL 0x00
#define RT_SP_DLM 0x01
#define MCR_DTR 0x01
#define MCR_RTS 0x02
#define MCR_OUT1 0x04
#define MCR_OUT2 0x08
#define MCR_LOOP 0x10
#define MCR_AFE 0x20
#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
#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
#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
#define LSR_TEMT 0x40
#define FCR_FIFO_ENABLE 0x01
#define FCR_INPUT_FIFO_RESET 0x02
#define FCR_OUTPUT_FIFO_RESET 0x04
struct rt_spmbx {
int frbs, avbs, fbyte, lbyte;
char *bufadr;
spinlock_t lock;
};
struct rt_spct_t {
int opened;
int base_adr, irq;
int mode, fifotrig;
int ier, mcr;
int error;
unsigned long just_onew, just_oner;
int tx_fifo_depth;
struct rt_spmbx ibuf, obuf;
void (*callback_fun)(int, int);
volatile int rxthrs, txthrs;
void (*err_callback_fun)(int);
RT_TASK *callback_task;
unsigned long callback_fun_usr;
unsigned long err_callback_fun_usr;
volatile unsigned long call_usr;
SEM txsem, rxsem;
struct rt_spct_t *next;
};
#endif /* RTAI_SPDRV_HW_H */

View file

@ -0,0 +1,79 @@
moduledir = @RTAI_MODULE_DIR@
includedir = $(prefix)/include/rtdm
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
librtdm_a_SOURCES = \
core.c \
device.c \
drvlib.c \
module.c \
proc.c \
rtai_taskq.c \
select.c
include_HEADERS = \
rtdm.h \
rtdm_driver.h \
rtserial.h \
xn.h \
rtai_taskq.h \
select.h
if CONFIG_KBUILD
rtai_rtdm$(modext): @RTAI_KBUILD_ENV@
rtai_rtdm$(modext): $(librtdm_a_SOURCES) FORCE
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ rtai_extradef="@RTAI_KMOD_CFLAGS@" \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
rm -f FORCE
distclean-local:
@RTAI_KBUILD_DISTCLEAN@
else
noinst_LIBRARIES = librtdm.a
librtdm_a_AR = $(CROSS_COMPILE)ar cru
INCLUDES = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I$(top_srcdir)/addons \
-I../../base/include \
-I../.. \
-I..
rtai_rtdm.o: librtdm.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: rtai_rtdm$(modext)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: rtai_rtdm$(modext)
$(mkinstalldirs) $(DESTDIR)$(moduledir) $(DESTDIR)$(includedir)
$(INSTALL_DATA) $< $(DESTDIR)$(moduledir)
uninstall-local:
$(RM) $(DESTDIR)$(moduledir)/rtai_rtdm$(modext)
.PHONY: FORCE
EXTRA_DIST = $(libmodule_SRC) Makefile.kbuild \
internal.h
# Always build if CONFIG_RTAI_RTDM is enabled
if CONFIG_RTAI_RTDM
OPTDIRS = lib
endif
SUBDIRS = $(OPTDIRS)

View file

@ -0,0 +1,12 @@
EXTRA_CFLAGS += -I$(rtai_srctree)/base/include \
-I$(rtai_srctree)/addons/rtdm \
-I$(rtai_srcdir)/.. \
-I$(src)/../../base/include \
-I$(src) \
-I$(src)/../.. \
$(rtai_extradef)
obj-m += $(rtai_target).o
$(rtai_target)-objs := $(rtai_objs)

1527
addons/rtdm/core.c Normal file

File diff suppressed because it is too large Load diff

522
addons/rtdm/device.c Normal file
View file

@ -0,0 +1,522 @@
/**
* @file
* Real-Time Driver Model for RTAI, device management
*
* @note Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>
* @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*!
* @addtogroup driverapi
* @{
*/
#include <linux/module.h>
#include <linux/delay.h>
#include "rtdm/internal.h"
#define SET_DEFAULT_OP(device, operation) \
(device).operation##_rt = (void *)rtdm_no_support; \
(device).operation##_nrt = (void *)rtdm_no_support
#define SET_DEFAULT_OP_IF_NULL(device, operation) \
if (!(device).operation##_rt) \
(device).operation##_rt = (void *)rtdm_no_support; \
if (!(device).operation##_nrt) \
(device).operation##_nrt = (void *)rtdm_no_support
#define ANY_HANDLER(device, operation) \
((device).operation##_rt || (device).operation##_nrt)
unsigned int devname_hashtab_size = DEF_DEVNAME_HASHTAB_SIZE;
unsigned int protocol_hashtab_size = DEF_PROTO_HASHTAB_SIZE;
module_param(devname_hashtab_size, uint, 0400);
module_param(protocol_hashtab_size, uint, 0400);
MODULE_PARM_DESC(devname_hashtab_size,
"Size of hash table for named devices (must be power of 2)");
MODULE_PARM_DESC(protocol_hashtab_size,
"Size of hash table for protocol devices "
"(must be power of 2)");
struct list_head *rtdm_named_devices; /* hash table */
struct list_head *rtdm_protocol_devices; /* hash table */
static int name_hashkey_mask;
static int proto_hashkey_mask;
int rtdm_apc;
EXPORT_SYMBOL(rtdm_apc);
struct semaphore nrt_dev_lock;
DEFINE_XNLOCK(rt_dev_lock);
#ifndef MODULE
int rtdm_initialised = 0;
#endif /* !MODULE */
int rtdm_no_support(void)
{
return -ENOSYS;
}
int rtdm_select_bind_no_support(struct rtdm_dev_context *context,
struct xnselector *selector,
unsigned type,
unsigned index)
{
return -EBADF;
}
static inline int get_name_hash(const char *str, int limit, int hashkey_mask)
{
int hash = 0;
while (*str != 0) {
hash += *str++;
if (--limit == 0)
break;
}
return hash & hashkey_mask;
}
static inline int get_proto_hash(int protocol_family, int socket_type)
{
return protocol_family & proto_hashkey_mask;
}
static inline void rtdm_reference_device(struct rtdm_device *device)
{
atomic_inc(&device->reserved.refcount);
}
struct rtdm_device *get_named_device(const char *name)
{
struct list_head *entry;
struct rtdm_device *device;
int hashkey;
spl_t s;
hashkey = get_name_hash(name, RTDM_MAX_DEVNAME_LEN, name_hashkey_mask);
xnlock_get_irqsave(&rt_dev_lock, s);
list_for_each(entry, &rtdm_named_devices[hashkey]) {
device = list_entry(entry, struct rtdm_device, reserved.entry);
if (strcmp(name, device->device_name) == 0) {
rtdm_reference_device(device);
xnlock_put_irqrestore(&rt_dev_lock, s);
return device;
}
}
xnlock_put_irqrestore(&rt_dev_lock, s);
return NULL;
}
struct rtdm_device *get_protocol_device(int protocol_family, int socket_type)
{
struct list_head *entry;
struct rtdm_device *device;
int hashkey;
spl_t s;
hashkey = get_proto_hash(protocol_family, socket_type);
xnlock_get_irqsave(&rt_dev_lock, s);
list_for_each(entry, &rtdm_protocol_devices[hashkey]) {
device = list_entry(entry, struct rtdm_device, reserved.entry);
if ((device->protocol_family == protocol_family) &&
(device->socket_type == socket_type)) {
rtdm_reference_device(device);
xnlock_put_irqrestore(&rt_dev_lock, s);
return device;
}
}
xnlock_put_irqrestore(&rt_dev_lock, s);
return NULL;
}
/*!
* @ingroup driverapi
* @defgroup devregister Device Registration Services
* @{
*/
/**
* @brief Register a RTDM device
*
* @param[in] device Pointer to structure describing the new device.
*
* @return 0 is returned upon success. Otherwise:
*
* - -EINVAL is returned if the device structure contains invalid entries.
* Check kernel log in this case.
*
* - -ENOMEM is returned if the context for an exclusive device cannot be
* allocated.
*
* - -EEXIST is returned if the specified device name of protocol ID is
* already in use.
*
* - -EAGAIN is returned if some /proc entry cannot be created.
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
*
* Rescheduling: never.
*/
int rtdm_dev_register(struct rtdm_device *device)
{
int hashkey;
spl_t s;
struct list_head *entry;
struct rtdm_device *existing_dev;
int ret;
/* Catch unsuccessful initialisation */
if (!rtdm_initialised)
return -ENOSYS;
/* Sanity check: structure version */
RTAI_ASSERT(RTDM, device->struct_version == RTDM_DEVICE_STRUCT_VER,
xnlogerr("RTDM: invalid rtdm_device version (%d, "
"required %d)\n", device->struct_version,
RTDM_DEVICE_STRUCT_VER);
return -EINVAL;);
/* Sanity check: proc_name specified? */
RTAI_ASSERT(RTDM, device->proc_name,
xnlogerr("RTDM: no /proc entry name specified\n");
return -EINVAL;);
switch (device->device_flags & RTDM_DEVICE_TYPE_MASK) {
case RTDM_NAMED_DEVICE:
/* Sanity check: any open handler? */
RTAI_ASSERT(RTDM, ANY_HANDLER(*device, open),
xnlogerr("RTDM: missing open handler\n");
return -EINVAL;);
if (device->open_rt &&
device->socket_rt != (void *)rtdm_no_support)
xnlogerr("RTDM: RT open handler is deprecated, "
"driver requires update.\n");
SET_DEFAULT_OP_IF_NULL(*device, open);
SET_DEFAULT_OP(*device, socket);
break;
case RTDM_PROTOCOL_DEVICE:
/* Sanity check: any socket handler? */
RTAI_ASSERT(RTDM, ANY_HANDLER(*device, socket),
xnlogerr("RTDM: missing socket handler\n");
return -EINVAL;);
if (device->socket_rt &&
device->socket_rt != (void *)rtdm_no_support)
xnlogerr("RTDM: RT socket creation handler is "
"deprecated, driver requires update.\n");
SET_DEFAULT_OP_IF_NULL(*device, socket);
SET_DEFAULT_OP(*device, open);
break;
default:
return -EINVAL;
}
/* Sanity check: non-RT close handler?
* (Always required for forced cleanup) */
if (!device->ops.close_nrt) {
xnlogerr("RTDM: missing non-RT close handler\n");
return -EINVAL;
}
if (device->ops.close_rt &&
device->ops.close_rt != (void *)rtdm_no_support)
xnlogerr("RTDM: RT close handler is deprecated, driver "
"requires update.\n");
else
device->ops.close_rt = (void *)rtdm_no_support;
SET_DEFAULT_OP_IF_NULL(device->ops, ioctl);
SET_DEFAULT_OP_IF_NULL(device->ops, read);
SET_DEFAULT_OP_IF_NULL(device->ops, write);
SET_DEFAULT_OP_IF_NULL(device->ops, recvmsg);
SET_DEFAULT_OP_IF_NULL(device->ops, sendmsg);
if (!device->ops.select_bind)
device->ops.select_bind = rtdm_select_bind_no_support;
atomic_set(&device->reserved.refcount, 0);
device->reserved.exclusive_context = NULL;
if (device->device_flags & RTDM_EXCLUSIVE) {
device->reserved.exclusive_context =
kmalloc(sizeof(struct rtdm_dev_context) +
device->context_size, GFP_KERNEL);
if (!device->reserved.exclusive_context) {
xnlogerr("RTDM: no memory for exclusive context "
"(context size: %ld)\n",
(long)device->context_size);
return -ENOMEM;
}
/* mark exclusive context as unused */
device->reserved.exclusive_context->device = NULL;
}
down(&nrt_dev_lock);
if ((device->device_flags & RTDM_DEVICE_TYPE_MASK) == RTDM_NAMED_DEVICE) {
trace_mark(xn_rtdm, nameddev_register, "device %p name %s "
"flags %d class %d sub_class %d profile_version %d "
"driver_version %d", device, device->device_name,
device->device_flags, device->device_class,
device->device_sub_class, device->profile_version,
device->driver_version);
hashkey =
get_name_hash(device->device_name, RTDM_MAX_DEVNAME_LEN,
name_hashkey_mask);
list_for_each(entry, &rtdm_named_devices[hashkey]) {
existing_dev =
list_entry(entry, struct rtdm_device,
reserved.entry);
if (strcmp(device->device_name,
existing_dev->device_name) == 0) {
ret = -EEXIST;
goto err;
}
}
ret = rtdm_proc_register_device(device);
if (ret)
goto err;
xnlock_get_irqsave(&rt_dev_lock, s);
list_add_tail(&device->reserved.entry,
&rtdm_named_devices[hashkey]);
xnlock_put_irqrestore(&rt_dev_lock, s);
up(&nrt_dev_lock);
} else {
trace_mark(xn_rtdm, protocol_register, "device %p "
"protocol_family %d socket_type %d flags %d "
"class %d sub_class %d profile_version %d "
"driver_version %d", device,
device->protocol_family, device->socket_type,
device->device_flags, device->device_class,
device->device_sub_class, device->profile_version,
device->driver_version);
hashkey = get_proto_hash(device->protocol_family,
device->socket_type);
list_for_each(entry, &rtdm_protocol_devices[hashkey]) {
existing_dev =
list_entry(entry, struct rtdm_device,
reserved.entry);
if ((device->protocol_family ==
existing_dev->protocol_family)
&& (device->socket_type ==
existing_dev->socket_type)) {
xnlogerr("RTDM: protocol %u:%u already "
"exists\n", device->protocol_family,
device->socket_type);
ret = -EEXIST;
goto err;
}
}
ret = rtdm_proc_register_device(device);
if (ret)
goto err;
xnlock_get_irqsave(&rt_dev_lock, s);
list_add_tail(&device->reserved.entry,
&rtdm_protocol_devices[hashkey]);
xnlock_put_irqrestore(&rt_dev_lock, s);
up(&nrt_dev_lock);
}
return 0;
err:
up(&nrt_dev_lock);
if (device->reserved.exclusive_context)
kfree(device->reserved.exclusive_context);
return ret;
}
EXPORT_SYMBOL(rtdm_dev_register);
/**
* @brief Unregisters a RTDM device
*
* @param[in] device Pointer to structure describing the device to be
* unregistered.
* @param[in] poll_delay Polling delay in milliseconds to check repeatedly for
* open instances of @a device, or 0 for non-blocking mode.
*
* @return 0 is returned upon success. Otherwise:
*
* - -ENODEV is returned if the device was not registered.
*
* - -EAGAIN is returned if the device is busy with open instances and 0 has
* been passed for @a poll_delay.
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
*
* Rescheduling: never.
*/
int rtdm_dev_unregister(struct rtdm_device *device, unsigned int poll_delay)
{
spl_t s;
struct rtdm_device *reg_dev;
unsigned long warned = 0;
if (!rtdm_initialised)
return -ENOSYS;
if ((device->device_flags & RTDM_DEVICE_TYPE_MASK) == RTDM_NAMED_DEVICE)
reg_dev = get_named_device(device->device_name);
else
reg_dev = get_protocol_device(device->protocol_family,
device->socket_type);
if (!reg_dev)
return -ENODEV;
trace_mark(xn_rtdm, dev_unregister, "device %p poll_delay %u",
device, poll_delay);
down(&nrt_dev_lock);
xnlock_get_irqsave(&rt_dev_lock, s);
while (atomic_read(&reg_dev->reserved.refcount) > 1) {
xnlock_put_irqrestore(&rt_dev_lock, s);
up(&nrt_dev_lock);
if (!poll_delay) {
rtdm_dereference_device(reg_dev);
trace_mark(xn_rtdm, dev_busy, "device %p", device);
return -EAGAIN;
}
if (!__test_and_set_bit(0, &warned))
xnlogwarn("RTDM: device %s still in use - waiting for "
"release...\n", reg_dev->device_name);
msleep(poll_delay);
trace_mark(xn_rtdm, dev_poll, "device %p", device);
down(&nrt_dev_lock);
xnlock_get_irqsave(&rt_dev_lock, s);
}
list_del(&reg_dev->reserved.entry);
xnlock_put_irqrestore(&rt_dev_lock, s);
rtdm_proc_unregister_device(device);
up(&nrt_dev_lock);
if (reg_dev->reserved.exclusive_context)
kfree(device->reserved.exclusive_context);
return 0;
}
EXPORT_SYMBOL(rtdm_dev_unregister);
/** @} */
int __init rtdm_dev_init(void)
{
int err, i;
sema_init(&nrt_dev_lock, 1);
rtdm_apc = rthal_apc_alloc("deferred RTDM close", rtdm_apc_handler,
NULL);
if (rtdm_apc < 0)
return rtdm_apc;
name_hashkey_mask = devname_hashtab_size - 1;
proto_hashkey_mask = protocol_hashtab_size - 1;
if (((devname_hashtab_size & name_hashkey_mask) != 0) ||
((protocol_hashtab_size & proto_hashkey_mask) != 0)) {
err = -EINVAL;
goto err_out1;
}
rtdm_named_devices = (struct list_head *)
kmalloc(devname_hashtab_size * sizeof(struct list_head),
GFP_KERNEL);
if (!rtdm_named_devices) {
err = -ENOMEM;
goto err_out1;
}
for (i = 0; i < devname_hashtab_size; i++)
INIT_LIST_HEAD(&rtdm_named_devices[i]);
rtdm_protocol_devices = (struct list_head *)
kmalloc(protocol_hashtab_size * sizeof(struct list_head),
GFP_KERNEL);
if (!rtdm_protocol_devices) {
err = -ENOMEM;
goto err_out2;
}
for (i = 0; i < protocol_hashtab_size; i++)
INIT_LIST_HEAD(&rtdm_protocol_devices[i]);
return 0;
err_out2:
kfree(rtdm_named_devices);
err_out1:
rthal_apc_free(rtdm_apc);
return err;
}
void rtdm_dev_cleanup(void)
{
/*
* Note: no need to flush the cleanup_queue as no device is allowed
* to deregister as long as there are references.
*/
rthal_apc_free(rtdm_apc);
kfree(rtdm_named_devices);
kfree(rtdm_protocol_devices);
}
/*@}*/

67
addons/rtdm/device.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTDM_DEVICE_H
#define _RTDM_DEVICE_H
#include <rtdm/rtdm_driver.h>
#include <linux/sem.h>
#define DEF_DEVNAME_HASHTAB_SIZE 256 /* entries in name hash table */
#define DEF_PROTO_HASHTAB_SIZE 256 /* entries in protocol hash table */
extern struct semaphore nrt_dev_lock;
extern xnlock_t rt_dev_lock;
extern unsigned int devname_hashtab_size;
extern unsigned int protocol_hashtab_size;
extern struct list_head *rtdm_named_devices;
extern struct list_head *rtdm_protocol_devices;
#ifdef MODULE
#define rtdm_initialised 1
#else /* !MODULE */
extern int rtdm_initialised;
#endif /* MODULE */
int rtdm_no_support(void);
struct rtdm_device *get_named_device(const char *name);
struct rtdm_device *get_protocol_device(int protocol_family, int socket_type);
static inline void rtdm_dereference_device(struct rtdm_device *device)
{
atomic_dec(&device->reserved.refcount);
}
int __init rtdm_dev_init(void);
static inline void rtdm_dev_cleanup(void)
{
kfree(rtdm_named_devices);
kfree(rtdm_protocol_devices);
}
#endif /* _RTDM_DEVICE_H */

2372
addons/rtdm/drvlib.c Normal file

File diff suppressed because it is too large Load diff

106
addons/rtdm/internal.h Normal file
View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2005-2007 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTDM_INTERNAL_H
#define _RTDM_INTERNAL_H
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/sem.h>
#include <rtdm/rtdm_driver.h>
#define RTDM_FD_MAX CONFIG_RTAI_RTDM_FD_MAX
#define DEF_DEVNAME_HASHTAB_SIZE 256 /* entries in name hash table */
#define DEF_PROTO_HASHTAB_SIZE 256 /* entries in protocol hash table */
struct rtdm_fildes {
struct rtdm_dev_context *context;
};
struct rtdm_process {
#ifdef CONFIG_PROC_FS
char name[32];
pid_t pid;
#endif /* CONFIG_PROC_FS */
};
DECLARE_EXTERN_XNLOCK(rt_fildes_lock);
DECLARE_EXTERN_XNLOCK(rt_dev_lock);
extern int __rtdm_muxid;
extern struct rtdm_fildes fildes_table[];
extern int open_fildes;
extern struct semaphore nrt_dev_lock;
extern unsigned int devname_hashtab_size;
extern unsigned int protocol_hashtab_size;
extern struct list_head *rtdm_named_devices;
extern struct list_head *rtdm_protocol_devices;
#ifdef MODULE
#define rtdm_initialised 1
#else /* !MODULE */
extern int rtdm_initialised;
#endif /* MODULE */
void cleanup_owned_contexts(void *user_info);
int rtdm_no_support(void);
struct rtdm_device *get_named_device(const char *name);
struct rtdm_device *get_protocol_device(int protocol_family, int socket_type);
static inline void rtdm_dereference_device(struct rtdm_device *device)
{
atomic_dec(&device->reserved.refcount);
}
int __init rtdm_dev_init(void);
void rtdm_dev_cleanup(void);
#ifdef CONFIG_PROC_FS
int __init rtdm_proc_init(void);
void rtdm_proc_cleanup(void);
int rtdm_proc_register_device(struct rtdm_device *device);
void rtdm_proc_unregister_device(struct rtdm_device *device);
#else
static inline int rtdm_proc_init(void)
{
return 0;
}
void rtdm_proc_cleanup(void)
{
}
static int rtdm_proc_register_device(struct rtdm_device *device)
{
return 0;
}
static void rtdm_proc_unregister_device(struct rtdm_device *device)
{
}
#endif
void rtdm_apc_handler(void *cookie);
#endif /* _RTDM_INTERNAL_H */

View file

@ -0,0 +1,19 @@
lib_LTLIBRARIES = librtdm.la
librtdm_la_LDFLAGS = -module -version-info 0:0:0
librtdm_la_SOURCES = \
services.c
INCLUDES = \
@RTAI_REAL_USER_CFLAGS@ \
-fno-inline \
-I../../../base/include \
-I$(top_srcdir)/base/include \
-I$(top_srcdir)/addons \
-I$(srcdir)/../..
if CONFIG_RTAI_DRIVERS_16550A
INCLUDES += -I$(top_srcdir)/addons/drivers/16550A
endif

View file

@ -0,0 +1,23 @@
/*
* Copyright (C) Pierre Cloutier <pcloutier@PoseidonControls.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the version 2 of the GNU Lesser
* General Public License as published by the Free Software
* Foundation.
*
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
//#define CONFIG_RTAI_LXRT_INLINE 0
#include <rtdm/rtdm.h>
#ifdef CONFIG_RTAI_DRIVERS_16550A
#include <rtdm/rtserial.h>
#endif /* CONFIG_RTAI_DRIVERS_16550A */

977
addons/rtdm/module.c Normal file
View file

@ -0,0 +1,977 @@
/**
* @file
* Real-Time Driver Model for RTAI
*
* @note Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>
* @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>
* @note Copyright (C) 2005-2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
* only for the adaption to RTAI.
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*!
* @defgroup rtdm Real-Time Driver Model
*
* The Real-Time Driver Model (RTDM) provides a unified interface to
* both users and developers of real-time device
* drivers. Specifically, it addresses the constraints of mixed
* RT/non-RT systems like RTAI. RTDM conforms to POSIX
* semantics (IEEE Std 1003.1) where available and applicable.
*/
/*!
* @ingroup rtdm
* @defgroup profiles Device Profiles
*
* Device profiles define which operation handlers a driver of a certain class
* has to implement, which name or protocol it has to register, which IOCTLs
* it has to provide, and further details. Sub-classes can be defined in order
* to extend a device profile with more hardware-specific functions.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <rtdm/rtdm.h>
#include <rtdm/internal.h>
#include <rtdm/rtdm_driver.h>
MODULE_DESCRIPTION("Real-Time Driver Model");
MODULE_AUTHOR("jan.kiszka@web.de");
MODULE_LICENSE("GPL");
static RTAI_SYSCALL_MODE int sys_rtdm_fdcount(void)
{
return RTDM_FD_MAX;
}
static RTAI_SYSCALL_MODE int sys_rtdm_open(const char *path, long oflag)
{
struct task_struct *curr = current;
char krnl_path[RTDM_MAX_DEVNAME_LEN + 1];
if (unlikely(!__xn_access_ok(curr, VERIFY_READ, path, sizeof(krnl_path)))) {
return -EFAULT;
}
__xn_copy_from_user(curr, krnl_path, path, sizeof(krnl_path) - 1);
krnl_path[sizeof(krnl_path) - 1] = '\0';
return __rt_dev_open(curr, (const char *)krnl_path, oflag);
}
static RTAI_SYSCALL_MODE int sys_rtdm_socket(long protocol_family, long socket_type, long protocol)
{
return __rt_dev_socket(current, protocol_family, socket_type, protocol);
}
static RTAI_SYSCALL_MODE int sys_rtdm_close(long fd, long forced)
{
return __rt_dev_close(current, fd);
}
static RTAI_SYSCALL_MODE int sys_rtdm_ioctl(long fd, long request, void *arg)
{
return __rt_dev_ioctl(current, fd, request, arg);
}
static RTAI_SYSCALL_MODE int sys_rtdm_read(long fd, void *buf, long nbytes)
{
return __rt_dev_read(current, fd, buf, nbytes);
}
static RTAI_SYSCALL_MODE int sys_rtdm_write(long fd, void *buf, long nbytes)
{
return __rt_dev_write(current, fd, buf, nbytes);
}
static RTAI_SYSCALL_MODE int sys_rtdm_recvmsg(long fd, struct msghdr *msg, long flags)
{
struct msghdr krnl_msg;
struct task_struct *curr = current;
int ret;
if (unlikely(!__xn_access_ok(curr, VERIFY_WRITE, msg, sizeof(krnl_msg)))) {
return -EFAULT;
}
__xn_copy_from_user(curr, &krnl_msg, msg, sizeof(krnl_msg));
if ((ret = __rt_dev_recvmsg(curr, fd, &krnl_msg, flags)) >= 0) {
__xn_copy_to_user(curr, msg, &krnl_msg, sizeof(krnl_msg));
}
return ret;
}
static RTAI_SYSCALL_MODE int sys_rtdm_sendmsg(long fd, const struct msghdr *msg, long flags)
{
struct msghdr krnl_msg;
struct task_struct *curr = current;
if (unlikely(!__xn_access_ok(curr, VERIFY_READ, msg, sizeof(krnl_msg)))) {
return -EFAULT;
}
__xn_copy_from_user(curr, &krnl_msg, msg, sizeof(krnl_msg));
return __rt_dev_sendmsg(curr, fd, &krnl_msg, flags);
}
static RTAI_SYSCALL_MODE int sys_rtdm_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, nanosecs_rel_t timeout)
{
return rt_dev_select(nfds, rfds, wfds, efds, timeout);
}
static struct rt_fun_entry rtdm[] = {
[__rtdm_fdcount] = { 0, sys_rtdm_fdcount },
[__rtdm_open] = { 0, sys_rtdm_open },
[__rtdm_socket] = { 0, sys_rtdm_socket },
[__rtdm_close] = { 0, sys_rtdm_close },
[__rtdm_ioctl] = { 0, sys_rtdm_ioctl },
[__rtdm_read] = { 0, sys_rtdm_read },
[__rtdm_write] = { 0, sys_rtdm_write },
[__rtdm_recvmsg] = { 0, sys_rtdm_recvmsg },
[__rtdm_sendmsg] = { 0, sys_rtdm_sendmsg },
[__rtdm_select] = { 0, sys_rtdm_select },
};
/* This is needed because RTDM interrupt handlers:
* - do no want immediate in handler rescheduling, RTAI can be configured
* to act in the same, way but might not have been enabled to do so;
* - may not reenable the PIC directly, assuming it will be done here;
* - may not propagate, assuming it will be done here as well.
* - might use shared interrupts its own way;
* REMARK: RTDM irqs management is as generic as its pet system dictates
* and there is no choice but doing the same as closely as possible;
* so this is an as verbatim as possible copy of what is needed from
* the RTDM pet system.
* REMINDER: the RTAI dispatcher cares mask/ack-ing anyhow, but RTDM will
* (must) provide the most suitable one for the shared case. */
#ifndef CONFIG_RTAI_SCHED_ISR_LOCK
extern struct { volatile int locked, rqsted; } rt_scheduling[];
extern void rtai_isr_sched_handle(int);
#define RTAI_SCHED_ISR_LOCK() \
do { \
int cpuid = rtai_cpuid(); \
if (!rt_scheduling[cpuid].locked++) { \
rt_scheduling[cpuid].rqsted = 0; \
}
#define RTAI_SCHED_ISR_UNLOCK() \
rtai_cli(); \
if (rt_scheduling[cpuid].locked && !(--rt_scheduling[cpuid].locked)) { \
if (rt_scheduling[cpuid].rqsted > 0) { \
rtai_isr_sched_handle(cpuid); \
} \
} \
} while (0)
#else /* !CONFIG_RTAI_SCHED_ISR_LOCK */
#define RTAI_SCHED_ISR_LOCK() \
do { } while (0)
#define RTAI_SCHED_ISR_UNLOCK() \
do { rtai_cli(); } while (0)
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
#define XNINTR_MAX_UNHANDLED 1000
DEFINE_PRIVATE_XNLOCK(intrlock);
static void xnintr_irq_handler(unsigned irq, void *cookie);
#ifdef CONFIG_RTAI_RTDM_SHIRQ
typedef struct xnintr_irq {
DECLARE_XNLOCK(lock);
xnintr_t *handlers;
int unhandled;
} ____cacheline_aligned_in_smp xnintr_irq_t;
static xnintr_irq_t xnirqs[RTHAL_NR_IRQS];
static inline xnintr_t *xnintr_shirq_first(unsigned irq)
{
return xnirqs[irq].handlers;
}
static inline xnintr_t *xnintr_shirq_next(xnintr_t *prev)
{
return prev->next;
}
/*
* Low-level interrupt handler dispatching the user-defined ISRs for
* shared interrupts -- Called with interrupts off.
*/
static void xnintr_shirq_handler(unsigned irq, void *cookie)
{
xnintr_irq_t *shirq = &xnirqs[irq];
xnintr_t *intr;
int s = 0, ret;
RTAI_SCHED_ISR_LOCK();
xnlock_get(&shirq->lock);
intr = shirq->handlers;
while (intr) {
ret = intr->isr(intr);
s |= ret;
if (ret & XN_ISR_HANDLED) {
xnstat_counter_inc(
&intr->stat[xnsched_cpu(sched)].hits);
}
intr = intr->next;
}
xnlock_put(&shirq->lock);
if (unlikely(s == XN_ISR_NONE)) {
if (++shirq->unhandled == XNINTR_MAX_UNHANDLED) {
xnlogerr("%s: IRQ%d not handled. Disabling IRQ "
"line.\n", __FUNCTION__, irq);
s |= XN_ISR_NOENABLE;
}
} else
shirq->unhandled = 0;
if (s & XN_ISR_PROPAGATE)
xnarch_chain_irq(irq);
else if (!(s & XN_ISR_NOENABLE))
xnarch_end_irq(irq);
RTAI_SCHED_ISR_UNLOCK();
}
/*
* Low-level interrupt handler dispatching the user-defined ISRs for
* shared edge-triggered interrupts -- Called with interrupts off.
*/
static void xnintr_edge_shirq_handler(unsigned irq, void *cookie)
{
const int MAX_EDGEIRQ_COUNTER = 128;
xnintr_irq_t *shirq = &xnirqs[irq];
int s = 0, counter = 0, ret, code;
struct xnintr *intr, *end = NULL;
RTAI_SCHED_ISR_LOCK();
xnlock_get(&shirq->lock);
intr = shirq->handlers;
while (intr != end) {
ret = intr->isr(intr);
code = ret & ~XN_ISR_BITMASK;
s |= ret;
if (code == XN_ISR_HANDLED) {
end = NULL;
xnstat_counter_inc(
&intr->stat[xnsched_cpu(sched)].hits);
} else if (end == NULL)
end = intr;
if (counter++ > MAX_EDGEIRQ_COUNTER)
break;
if (!(intr = intr->next))
intr = shirq->handlers;
}
xnlock_put(&shirq->lock);
if (counter > MAX_EDGEIRQ_COUNTER)
xnlogerr
("xnintr_edge_shirq_handler() : failed to get the IRQ%d line free.\n",
irq);
if (unlikely(s == XN_ISR_NONE)) {
if (++shirq->unhandled == XNINTR_MAX_UNHANDLED) {
xnlogerr("%s: IRQ%d not handled. Disabling IRQ "
"line.\n", __FUNCTION__, irq);
s |= XN_ISR_NOENABLE;
}
} else
shirq->unhandled = 0;
if (s & XN_ISR_PROPAGATE)
xnarch_chain_irq(irq);
else if (!(s & XN_ISR_NOENABLE))
xnarch_end_irq(irq);
RTAI_SCHED_ISR_UNLOCK();
}
static inline int xnintr_irq_attach(xnintr_t *intr)
{
xnintr_irq_t *shirq = &xnirqs[intr->irq];
xnintr_t *prev, **p = &shirq->handlers;
int err;
if ((prev = *p) != NULL) {
/* Check on whether the shared mode is allowed. */
if (!(prev->flags & intr->flags & XN_ISR_SHARED) ||
(prev->iack != intr->iack)
|| ((prev->flags & XN_ISR_EDGE) !=
(intr->flags & XN_ISR_EDGE)))
return -EBUSY;
/* Get a position at the end of the list to insert the new element. */
while (prev) {
p = &prev->next;
prev = *p;
}
} else {
/* Initialize the corresponding interrupt channel */
void (*handler) (unsigned, void *) = &xnintr_irq_handler;
if (intr->flags & XN_ISR_SHARED) {
if (intr->flags & XN_ISR_EDGE)
handler = &xnintr_edge_shirq_handler;
else
handler = &xnintr_shirq_handler;
}
shirq->unhandled = 0;
err = xnarch_hook_irq(intr->irq, handler,
intr->iack, intr);
if (err)
return err;
}
intr->next = NULL;
/* Add the given interrupt object. No need to synchronise with the IRQ
handler, we are only extending the chain. */
*p = intr;
return 0;
}
static inline int xnintr_irq_detach(xnintr_t *intr)
{
xnintr_irq_t *shirq = &xnirqs[intr->irq];
xnintr_t *e, **p = &shirq->handlers;
int err = 0;
while ((e = *p) != NULL) {
if (e == intr) {
/* Remove the given interrupt object from the list. */
xnlock_get(&shirq->lock);
*p = e->next;
xnlock_put(&shirq->lock);
/* Release the IRQ line if this was the last user */
if (shirq->handlers == NULL)
err = xnarch_release_irq(intr->irq);
return err;
}
p = &e->next;
}
xnlogerr("attempted to detach a non previously attached interrupt "
"object.\n");
return err;
}
#else /* !CONFIG_RTAI_RTDM_SHIRQ */
#ifdef CONFIG_SMP
typedef struct xnintr_irq {
DECLARE_XNLOCK(lock);
} ____cacheline_aligned_in_smp xnintr_irq_t;
static xnintr_irq_t xnirqs[RTHAL_NR_IRQS];
#endif /* CONFIG_SMP */
static inline xnintr_t *xnintr_shirq_first(unsigned irq)
{
return xnarch_get_irq_cookie(irq);
}
static inline xnintr_t *xnintr_shirq_next(xnintr_t *prev)
{
return NULL;
}
static inline int xnintr_irq_attach(xnintr_t *intr)
{
return xnarch_hook_irq(intr->irq, &xnintr_irq_handler,
intr->iack, intr);
}
static inline int xnintr_irq_detach(xnintr_t *intr)
{
int irq = intr->irq, ret;
xnlock_get(&xnirqs[irq].lock);
ret = xnarch_release_irq(irq);
xnlock_put(&xnirqs[irq].lock);
return ret;
}
#endif /* !CONFIG_RTAI_RTDM_SHIRQ */
/*
* Low-level interrupt handler dispatching non-shared ISRs -- Called with
* interrupts off.
*/
static void xnintr_irq_handler(unsigned irq, void *cookie)
{
struct xnintr *intr;
int s;
RTAI_SCHED_ISR_LOCK();
xnlock_get(&xnirqs[irq].lock);
#ifdef CONFIG_SMP
/*
* In SMP case, we have to reload the cookie under the per-IRQ
* lock to avoid racing with xnintr_detach. However, we
* assume that no CPU migration will occur while running the
* interrupt service routine, so the scheduler pointer will
* remain valid throughout this function.
*/
intr = xnarch_get_irq_cookie(irq);
if (unlikely(!intr)) {
s = 0;
goto unlock_and_exit;
}
#else
/* cookie always valid, attach/detach happens with IRQs disabled */
intr = cookie;
#endif
s = intr->isr(intr);
if (unlikely(s == XN_ISR_NONE)) {
if (++intr->unhandled == XNINTR_MAX_UNHANDLED) {
xnlogerr("%s: IRQ%d not handled. Disabling IRQ "
"line.\n", __FUNCTION__, irq);
s |= XN_ISR_NOENABLE;
}
} else {
xnstat_counter_inc(&intr->stat[xnsched_cpu(sched)].hits);
intr->unhandled = 0;
}
#ifdef CONFIG_SMP
unlock_and_exit:
#endif
xnlock_put(&xnirqs[irq].lock);
if (s & XN_ISR_PROPAGATE)
xnarch_chain_irq(irq);
else if (!(s & XN_ISR_NOENABLE))
xnarch_end_irq(irq);
RTAI_SCHED_ISR_UNLOCK();
}
int xnintr_mount(void)
{
int i;
for (i = 0; i < RTHAL_NR_IRQS; ++i)
xnlock_init(&xnirqs[i].lock);
return 0;
}
int xnintr_init(xnintr_t *intr,
const char *name,
unsigned irq, xnisr_t isr, xniack_t iack, xnflags_t flags)
{
if (irq >= RTHAL_NR_IRQS)
return -EINVAL;
intr->irq = irq;
intr->isr = isr;
intr->iack = iack;
intr->cookie = NULL;
intr->name = name ? : "<unknown>";
intr->flags = flags;
intr->unhandled = 0;
memset(&intr->stat, 0, sizeof(intr->stat));
#ifdef CONFIG_RTAI_RTDM_SHIRQ
intr->next = NULL;
#endif
return 0;
}
EXPORT_SYMBOL_GPL(xnintr_init);
int xnintr_destroy(xnintr_t *intr)
{
return xnintr_detach(intr);
}
EXPORT_SYMBOL_GPL(xnintr_destroy);
int xnintr_attach(xnintr_t *intr, void *cookie)
{
int ret;
spl_t s;
intr->cookie = cookie;
memset(&intr->stat, 0, sizeof(intr->stat));
#ifdef CONFIG_SMP
xnarch_set_irq_affinity(intr->irq, nkaffinity);
#endif /* CONFIG_SMP */
xnlock_get_irqsave(&intrlock, s);
if (__testbits(intr->flags, XN_ISR_ATTACHED)) {
ret = -EBUSY;
goto out;
}
ret = xnintr_irq_attach(intr);
if (ret)
goto out;
__setbits(intr->flags, XN_ISR_ATTACHED);
out:
xnlock_put_irqrestore(&intrlock, s);
return ret;
}
EXPORT_SYMBOL_GPL(xnintr_attach);
int xnintr_detach(xnintr_t *intr)
{
int ret;
spl_t s;
xnlock_get_irqsave(&intrlock, s);
if (!__testbits(intr->flags, XN_ISR_ATTACHED)) {
ret = -EINVAL;
goto out;
}
__clrbits(intr->flags, XN_ISR_ATTACHED);
ret = xnintr_irq_detach(intr);
if (ret)
goto out;
out:
xnlock_put_irqrestore(&intrlock, s);
return ret;
}
EXPORT_SYMBOL_GPL(xnintr_detach);
int xnintr_enable(xnintr_t *intr)
{
rt_enable_irq(intr->irq);
return 0;
}
EXPORT_SYMBOL_GPL(xnintr_enable);
int xnintr_disable(xnintr_t *intr)
{
rt_disable_irq(intr->irq);
return 0;
}
EXPORT_SYMBOL_GPL(xnintr_disable);
typedef cpumask_t xnarch_cpumask_t;
void xnintr_affinity(xnintr_t *intr, xnarch_cpumask_t cpumask)
{
trace_mark(xn_nucleus, irq_affinity, "irq %u %lu",
intr->irq, *(unsigned long *)&cpumask);
xnarch_set_irq_affinity(intr->irq, cpumask);
}
EXPORT_SYMBOL_GPL(xnintr_affinity);
extern struct epoch_struct boot_epoch;
#ifdef CONFIG_SMP
#define NUM_CPUS RTAI_NR_CPUS
#define TIMED_TIMER_CPUID (timed_timer->cpuid)
#define TIMER_CPUID (timer->cpuid)
#define LIST_CPUID (cpuid)
#else
#define NUM_CPUS 1
#define TIMED_TIMER_CPUID (0)
#define TIMER_CPUID (0)
#define LIST_CPUID (0)
#endif
static struct rtdm_timer_struct timers_list[NUM_CPUS] =
{ { &timers_list[0], &timers_list[0], RT_SCHED_LOWEST_PRIORITY, 0, RT_TIME_END, 0LL, NULL, 0UL,
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
{ NULL }
#endif
}, };
//static spinlock_t timers_lock[NUM_CPUS] = { SPIN_LOCK_UNLOCKED, };
static spinlock_t timers_lock[NUM_CPUS] = { __SPIN_LOCK_UNLOCKED(timers_lock[0]), };
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
/* BINARY TREE */
static inline void enq_timer(struct rtdm_timer_struct *timed_timer)
{
struct rtdm_timer_struct *timerh, *tmrnxt, *timer;
rb_node_t **rbtn, *rbtpn = NULL;
timer = timerh = &timers_list[TIMED_TIMER_CPUID];
rbtn = &timerh->rbr.rb_node;
while (*rbtn) {
rbtpn = *rbtn;
tmrnxt = rb_entry(rbtpn, struct rtdm_timer_struct, rbn);
if (timer->firing_time > tmrnxt->firing_time) {
rbtn = &(rbtpn)->rb_right;
} else {
rbtn = &(rbtpn)->rb_left;
timer = tmrnxt;
}
}
rb_link_node(&timed_timer->rbn, rbtpn, rbtn);
rb_insert_color(&timed_timer->rbn, &timerh->rbr);
timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer;
timed_timer->next = timer;
}
#define rb_erase_timer(timer) \
rb_erase(&(timer)->rbn, &timers_list[NUM_CPUS > 1 ? (timer)->cpuid : 0].rbr)
#else /* !CONFIG_RTAI_LONG_TIMED_LIST */
/* LINEAR */
static inline void enq_timer(struct rtdm_timer_struct *timed_timer)
{
struct rtdm_timer_struct *timer;
timer = &timers_list[TIMED_TIMER_CPUID];
while (timed_timer->firing_time > (timer = timer->next)->firing_time);
timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer;
timed_timer->next = timer;
}
#define rb_erase_timer(timer)
#endif /* CONFIG_RTAI_LONG_TIMED_LIST */
static inline void rem_timer(struct rtdm_timer_struct *timer)
{
(timer->next)->prev = timer->prev;
(timer->prev)->next = timer->next;
timer->next = timer->prev = timer;
rb_erase_timer(timer);
}
static RT_TASK timers_manager[NUM_CPUS];
static inline void asgn_min_prio(int cpuid)
{
RT_TASK *timer_manager;
struct rtdm_timer_struct *timer, *timerl;
spinlock_t *lock;
unsigned long flags;
int priority;
priority = (timer = (timerl = &timers_list[LIST_CPUID])->next)->priority;
flags = rt_spin_lock_irqsave(lock = &timers_lock[LIST_CPUID]);
while ((timer = timer->next) != timerl) {
if (timer->priority < priority) {
priority = timer->priority;
}
rt_spin_unlock_irqrestore(flags, lock);
flags = rt_spin_lock_irqsave(lock);
}
rt_spin_unlock_irqrestore(flags, lock);
flags = rt_global_save_flags_and_cli();
if ((timer_manager = &timers_manager[LIST_CPUID])->priority > priority) {
timer_manager->priority = priority;
if (timer_manager->state == RT_SCHED_READY) {
rem_ready_task(timer_manager);
enq_ready_task(timer_manager);
}
}
rt_global_restore_flags(flags);
}
RTAI_SYSCALL_MODE int rt_timer_insert(struct rtdm_timer_struct *timer, int priority, RTIME firing_time, RTIME period, void (*handler)(unsigned long), unsigned long data)
{
spinlock_t *lock;
unsigned long flags, cpuid;
RT_TASK *timer_manager;
if (!handler) {
return -EINVAL;
}
timer->handler = handler;
timer->data = data;
timer->priority = priority;
timer->firing_time = firing_time;
timer->period = period;
REALTIME2COUNT(firing_time)
timer->cpuid = cpuid = NUM_CPUS > 1 ? rtai_cpuid() : 0;
// timer insertion in timers_list
flags = rt_spin_lock_irqsave(lock = &timers_lock[LIST_CPUID]);
enq_timer(timer);
rt_spin_unlock_irqrestore(flags, lock);
// timers_manager priority inheritance
if (timer->priority < (timer_manager = &timers_manager[LIST_CPUID])->priority) {
timer_manager->priority = timer->priority;
}
// timers_task deadline inheritance
flags = rt_global_save_flags_and_cli();
if (timers_list[LIST_CPUID].next == timer && (timer_manager->state & RT_SCHED_DELAYED) && firing_time < timer_manager->resume_time) {
timer_manager->resume_time = firing_time;
rem_timed_task(timer_manager);
enq_timed_task(timer_manager);
rt_schedule();
}
rt_global_restore_flags(flags);
return 0;
}
RTAI_SYSCALL_MODE void rt_timer_remove(struct rtdm_timer_struct *timer)
{
if (timer->next != timer && timer->prev != timer) {
spinlock_t *lock;
unsigned long flags;
flags = rt_spin_lock_irqsave(lock = &timers_lock[TIMER_CPUID]);
rem_timer(timer);
rt_spin_unlock_irqrestore(flags, lock);
asgn_min_prio(TIMER_CPUID);
}
}
static int TimersManagerPrio = 0;
RTAI_MODULE_PARM(TimersManagerPrio, int);
static void rt_timers_manager(long cpuid)
{
RTIME now;
RT_TASK *timer_manager;
struct rtdm_timer_struct *tmr, *timer, *timerl;
spinlock_t *lock;
unsigned long flags, timer_tol;
int priority;
timer_manager = &timers_manager[LIST_CPUID];
timerl = &timers_list[LIST_CPUID];
lock = &timers_lock[LIST_CPUID];
timer_tol = tuned.timers_tol[LIST_CPUID];
while (1) {
rt_sleep_until((timerl->next)->firing_time);
now = rt_get_time() + timer_tol;
while (1) {
tmr = timer = timerl;
priority = RT_SCHED_LOWEST_PRIORITY;
flags = rt_spin_lock_irqsave(lock);
while ((tmr = tmr->next)->firing_time <= now) {
if (tmr->priority < priority) {
priority = (timer = tmr)->priority;
}
}
rt_spin_unlock_irqrestore(flags, lock);
if (timer == timerl) {
if (timer_manager->priority > TimersManagerPrio) {
timer_manager->priority = TimersManagerPrio;
}
break;
}
timer_manager->priority = priority;
flags = rt_spin_lock_irqsave(lock);
rem_timer(timer);
if (timer->period) {
timer->firing_time += timer->period;
enq_timer(timer);
}
rt_spin_unlock_irqrestore(flags, lock);
timer->handler(timer->data);
}
asgn_min_prio(LIST_CPUID);
}
}
static int TimersManagerStacksize = 8192;
RTAI_MODULE_PARM(TimersManagerStacksize, int);
static int rtai_timers_init(void)
{
int cpuid;
for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
timers_lock[cpuid] = timers_lock[0];
timers_list[cpuid] = timers_list[0];
timers_list[cpuid].cpuid = cpuid;
timers_list[cpuid].next = timers_list[cpuid].prev = &timers_list[cpuid];
}
for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
rt_task_init_cpuid(&timers_manager[cpuid], rt_timers_manager, cpuid, TimersManagerStacksize, TimersManagerPrio, 0, NULL, cpuid);
rt_task_resume(&timers_manager[cpuid]);
}
return 0;
}
static void rtai_timers_cleanup(void)
{
int cpuid;
for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
rt_task_delete(&timers_manager[cpuid]);
}
}
EXPORT_SYMBOL(rt_timer_insert);
EXPORT_SYMBOL(rt_timer_remove);
int __init rtdm_skin_init(void)
{
int err;
rtai_timers_init();
if(set_rt_fun_ext_index(rtdm, RTDM_INDX)) {
printk("LXRT extension %d already in use. Recompile RTDM with a different extension index\n", RTDM_INDX);
return -EACCES;
}
if ((err = rtdm_dev_init())) {
goto fail;
}
xnintr_mount();
#ifdef CONFIG_RTAI_RTDM_SELECT
if (xnselect_mount()) {
goto cleanup_core;
}
#endif
#ifdef CONFIG_PROC_FS
if ((err = rtdm_proc_init())) {
goto cleanup_core;
}
#endif /* CONFIG_PROC_FS */
printk("RTDM started.\n");
return 0;
cleanup_core:
#ifdef CONFIG_RTAI_RTDM_SELECT
xnselect_umount();
#endif
rtdm_dev_cleanup();
#ifdef CONFIG_PROC_FS
rtdm_proc_cleanup();
#endif /* CONFIG_PROC_FS */
fail:
return err;
}
void __exit rtdm_skin_exit(void)
{
#ifdef CONFIG_RTAI_RTDM_SELECT
xnselect_umount();
#endif
rtai_timers_cleanup();
rtdm_dev_cleanup();
reset_rt_fun_ext_index(rtdm, RTDM_INDX);
#ifdef CONFIG_PROC_FS
rtdm_proc_cleanup();
#endif /* CONFIG_PROC_FS */
printk("RTDM stopped.\n");
}
module_init(rtdm_skin_init);
module_exit(rtdm_skin_exit);

317
addons/rtdm/proc.c Normal file
View file

@ -0,0 +1,317 @@
/*
* Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>.
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "rtdm/internal.h"
/* Derived from Erwin Rol's rtai_proc_fs.h.
Assumes that output fits into the provided buffer. */
#define RTDM_PROC_PRINT_VARS(MAX_BLOCK_LEN) \
const int max_block_len = MAX_BLOCK_LEN; \
off_t __limit = count - MAX_BLOCK_LEN; \
int __len = 0; \
\
*eof = 1; \
if (count < MAX_BLOCK_LEN) \
return 0
#define RTDM_PROC_PRINT(fmt, args...) \
({ \
__len += snprintf(buf + __len, max_block_len, fmt, ##args); \
(__len <= __limit); \
})
#define RTDM_PROC_PRINT_DONE \
return __len
struct proc_dir_entry *rtdm_proc_root; /* /proc/rtai/rtdm */
static int proc_read_named_devs(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int i;
struct list_head *entry;
struct rtdm_device *device;
RTDM_PROC_PRINT_VARS(80);
if (down_interruptible(&nrt_dev_lock))
return -ERESTARTSYS;
if (!RTDM_PROC_PRINT("Hash\tName\t\t\t\tDriver\t\t/proc\n"))
goto done;
for (i = 0; i < devname_hashtab_size; i++)
list_for_each(entry, &rtdm_named_devices[i]) {
device = list_entry(entry, struct rtdm_device,
reserved.entry);
if (!RTDM_PROC_PRINT("%02X\t%-31s\t%-15s\t%s\n",
i, device->device_name,
device->driver_name,
device->proc_name))
break;
}
done:
up(&nrt_dev_lock);
RTDM_PROC_PRINT_DONE;
}
static int proc_read_proto_devs(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int i;
struct list_head *entry;
struct rtdm_device *device;
char txt[32];
RTDM_PROC_PRINT_VARS(80);
if (down_interruptible(&nrt_dev_lock))
return -ERESTARTSYS;
if (!RTDM_PROC_PRINT("Hash\tProtocolFamily:SocketType\tDriver\t\t"
"/proc\n"))
goto done;
for (i = 0; i < protocol_hashtab_size; i++)
list_for_each(entry, &rtdm_protocol_devices[i]) {
device = list_entry(entry, struct rtdm_device,
reserved.entry);
snprintf(txt, sizeof(txt), "%u:%u",
device->protocol_family, device->socket_type);
if (!RTDM_PROC_PRINT("%02X\t%-31s\t%-15s\t%s\n", i,
txt, device->driver_name,
device->proc_name))
break;
}
done:
up(&nrt_dev_lock);
RTDM_PROC_PRINT_DONE;
}
static int proc_read_open_fildes(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int i;
int close_lock_count;
struct rtdm_device *device;
struct rtdm_process owner;
spl_t s;
RTDM_PROC_PRINT_VARS(80);
if (!RTDM_PROC_PRINT("Index\tLocked\tDevice\t\tOwner [PID]\n"))
goto done;
if (down_interruptible(&nrt_dev_lock))
return -ERESTARTSYS;
for (i = 0; i < RTDM_FD_MAX; i++) {
struct rtdm_dev_context *context;
xnlock_get_irqsave(&rt_fildes_lock, s);
context = fildes_table[i].context;
if (!context) {
xnlock_put_irqrestore(&rt_fildes_lock, s);
continue;
}
close_lock_count = atomic_read(&context->close_lock_count);
device = context->device;
if (context->reserved.owner)
memcpy(&owner, context->reserved.owner, sizeof(owner));
else {
strcpy(owner.name, "<kernel>");
owner.pid = -1;
}
xnlock_put_irqrestore(&rt_fildes_lock, s);
if (!RTDM_PROC_PRINT("%d\t%d\t%-15s %s [%d]\n", i,
close_lock_count,
(device->device_flags&RTDM_NAMED_DEVICE) ?
device->device_name : device->proc_name,
owner.name, owner.pid))
break;
}
up(&nrt_dev_lock);
done:
RTDM_PROC_PRINT_DONE;
}
static int proc_kill_open_fildes(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char krnl_buf[32];
int fd;
int res;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (count >= sizeof(krnl_buf))
return -EINVAL;
if (copy_from_user(krnl_buf, buffer, count))
return -EFAULT;
krnl_buf[count] = '\0';
if (!sscanf(krnl_buf, "%d", &fd))
return -EINVAL;
res = __rt_dev_close(current, fd);
if (res < 0)
return res;
return count;
}
static int proc_read_fildes(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
RTDM_PROC_PRINT_VARS(80);
RTDM_PROC_PRINT("total=%d:open=%d:free=%d\n", RTDM_FD_MAX,
open_fildes, RTDM_FD_MAX - open_fildes);
RTDM_PROC_PRINT_DONE;
}
static int proc_read_dev_info(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
/* accessing the device during unregister (remove_proc_entry) might be
racy, but no official workaround is known yet */
struct rtdm_device *device = data;
RTDM_PROC_PRINT_VARS(256);
if (!RTDM_PROC_PRINT("driver:\t\t%s\nversion:\t%d.%d.%d\n",
device->driver_name,
RTDM_DRIVER_MAJOR_VER(device->driver_version),
RTDM_DRIVER_MINOR_VER(device->driver_version),
RTDM_DRIVER_PATCH_VER(device->driver_version)))
goto done;
if (!RTDM_PROC_PRINT("peripheral:\t%s\nprovider:\t%s\n",
device->peripheral_name, device->provider_name))
goto done;
if (!RTDM_PROC_PRINT("class:\t\t%d\nsub-class:\t%d\n",
device->device_class, device->device_sub_class))
goto done;
if (!RTDM_PROC_PRINT("flags:\t\t%s%s%s\n",
(device->device_flags & RTDM_EXCLUSIVE) ?
"EXCLUSIVE " : "",
(device->device_flags & RTDM_NAMED_DEVICE) ?
"NAMED_DEVICE " : "",
(device->device_flags & RTDM_PROTOCOL_DEVICE) ?
"PROTOCOL_DEVICE " : ""))
goto done;
RTDM_PROC_PRINT("lock count:\t%d\n",
atomic_read(&device->reserved.refcount));
done:
RTDM_PROC_PRINT_DONE;
}
int rtdm_proc_register_device(struct rtdm_device *device)
{
struct proc_dir_entry *dev_dir;
struct proc_dir_entry *proc_entry;
dev_dir = create_proc_entry(device->proc_name, S_IFDIR, rtdm_proc_root);
if (!dev_dir)
goto err_out;
proc_entry = create_proc_entry("information", S_IFREG | S_IRUGO,
dev_dir);
if (!proc_entry) {
remove_proc_entry(device->proc_name, rtdm_proc_root);
goto err_out;
}
proc_entry->data = device;
proc_entry->read_proc = proc_read_dev_info;
device->proc_entry = dev_dir;
return 0;
err_out:
xnlogerr("RTDM: error while creating device proc entry\n");
return -EAGAIN;
}
void rtdm_proc_unregister_device(struct rtdm_device *device)
{
remove_proc_entry("information", device->proc_entry);
remove_proc_entry(device->proc_name, rtdm_proc_root);
}
int __init rtdm_proc_init(void)
{
struct proc_dir_entry *proc_entry;
/* Initialise /proc entries */
rtdm_proc_root = create_proc_entry("rtai/rtdm", S_IFDIR, NULL);
if (!rtdm_proc_root)
return -EAGAIN;
proc_entry = create_proc_entry("named_devices", S_IFREG | S_IRUGO,
rtdm_proc_root);
if (!proc_entry)
return -EAGAIN;
proc_entry->read_proc = proc_read_named_devs;
proc_entry = create_proc_entry("protocol_devices", S_IFREG | S_IRUGO,
rtdm_proc_root);
if (!proc_entry)
return -EAGAIN;
proc_entry->read_proc = proc_read_proto_devs;
proc_entry =
create_proc_entry("open_fildes", S_IFREG | S_IRUGO, rtdm_proc_root);
if (!proc_entry)
return -EAGAIN;
proc_entry->read_proc = proc_read_open_fildes;
proc_entry->write_proc = proc_kill_open_fildes;
proc_entry =
create_proc_entry("fildes", S_IFREG | S_IRUGO, rtdm_proc_root);
if (!proc_entry)
return -EAGAIN;
proc_entry->read_proc = proc_read_fildes;
return 0;
}
void rtdm_proc_cleanup(void)
{
remove_proc_entry("fildes", rtdm_proc_root);
remove_proc_entry("open_fildes", rtdm_proc_root);
remove_proc_entry("protocol_devices", rtdm_proc_root);
remove_proc_entry("named_devices", rtdm_proc_root);
remove_proc_entry("rtai/rtdm", NULL);
}

32
addons/rtdm/proc.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>.
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTDM_PROC_H
#define _RTDM_PROC_H
extern struct proc_dir_entry *rtdm_proc_root;
int rtdm_proc_register_device(struct rtdm_device* device);
int __init rtdm_proc_init(void);
void rtdm_proc_cleanup(void);
#endif /* _RTDM_PROC_H */

164
addons/rtdm/rtai_taskq.c Normal file
View file

@ -0,0 +1,164 @@
/*
* Copyright (C) 2008-2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include "rtai_taskq.h"
#ifdef CONFIG_SMP
volatile unsigned long tosched_mask;
#endif
void rt_schedule_readied(void)
{
unsigned long flags;
#ifdef CONFIG_SMP
unsigned long cpumask, rmask, lmask;
flags = rt_global_save_flags_and_cli();
lmask = tosched_mask;
tosched_mask = 0;
rt_global_restore_flags(flags);
rmask = lmask & ~(cpumask = (1 << rtai_cpuid()));
if (rmask) {
rtai_save_flags_and_cli(flags);
send_sched_ipi(rmask);
rtai_restore_flags(flags);
}
if (lmask | cpumask)
#endif
{
flags = rt_global_save_flags_and_cli();
rt_schedule();
rt_global_restore_flags(flags);
}
}
EXPORT_SYMBOL(rt_schedule_readied);
void rt_taskq_init(TASKQ *taskq, unsigned long type)
{
taskq->qtype = (type & TASKQ_FIFO) ? 1 : 0;
taskq->queue = (QUEUE) { &taskq->queue, &taskq->queue, NULL };
}
EXPORT_SYMBOL(rt_taskq_init);
RT_TASK *rt_taskq_ready_one(TASKQ *taskq)
{
unsigned long flags;
RT_TASK *task = NULL;
flags = rt_global_save_flags_and_cli();
if ((task = (taskq->queue.next)->task)) {
dequeue_blocked(task);
rem_timed_task(task);
if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_TASKQ | RT_SCHED_DELAYED)) == RT_SCHED_READY) {
enq_ready_task(task);
TOSCHED_TASK(task);
}
}
rt_global_restore_flags(flags);
return task;
}
EXPORT_SYMBOL(rt_taskq_ready_one);
int rt_taskq_ready_all(TASKQ *taskq, unsigned long why)
{
unsigned long flags, tosched;
RT_TASK *task;
QUEUE *q;
tosched = 0;
q = &(taskq->queue);
flags = rt_global_save_flags_and_cli();
while ((q = q->next) != &(taskq->queue)) {
if ((task = q->task)) {
dequeue_blocked(task = q->task);
rem_timed_task(task);
task->retval = why;
if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_TASKQ | RT_SCHED_DELAYED)) == RT_SCHED_READY) {
enq_ready_task(task);
TOSCHED_TASK(task);
tosched = 1;
}
}
rt_global_restore_flags(flags);
flags = rt_global_save_flags_and_cli();
}
rt_global_restore_flags(flags);
return tosched;
}
EXPORT_SYMBOL(rt_taskq_ready_all);
void rt_taskq_wait(TASKQ *taskq)
{
RT_TASK *rt_current;
unsigned long flags;
void *retp;
flags = rt_global_save_flags_and_cli();
rt_current = RT_CURRENT;
rt_current->retval = 0;
rt_current->state |= RT_SCHED_TASKQ;
rem_ready_current(rt_current);
enqueue_blocked(rt_current, &taskq->queue, taskq->qtype);
rt_schedule();
if (unlikely((retp = rt_current->blocked_on) != NULL)) {
if (likely(retp != RTP_OBJREM)) {
dequeue_blocked(rt_current);
rt_current->retval = XNBREAK;
} else {
rt_current->prio_passed_to = NULL;
rt_current->retval = XNRMID;
}
}
rt_global_restore_flags(flags);
}
EXPORT_SYMBOL(rt_taskq_wait);
void rt_taskq_wait_until(TASKQ *taskq, RTIME time)
{
DECLARE_RT_CURRENT;
unsigned long flags;
void *retp;
REALTIME2COUNT(time);
flags = rt_global_save_flags_and_cli();
ASSIGN_RT_CURRENT;
rt_current->retval = 0;
rt_current->blocked_on = &taskq->queue;
if ((rt_current->resume_time = time) > rt_time_h) {
rt_current->state |= (RT_SCHED_TASKQ | RT_SCHED_DELAYED);
rem_ready_current(rt_current);
enqueue_blocked(rt_current, &taskq->queue, taskq->qtype);
enq_timed_task(rt_current);
rt_schedule();
}
if (unlikely((retp = rt_current->blocked_on) != NULL)) {
if (likely(retp != RTP_OBJREM)) {
dequeue_blocked(rt_current);
rt_current->retval = retp > RTP_HIGERR ? XNTIMEO : XNBREAK;
} else {
rt_current->prio_passed_to = NULL;
rt_current->retval = XNRMID;
}
}
rt_global_restore_flags(flags);
}
EXPORT_SYMBOL(rt_taskq_wait_until);

76
addons/rtdm/rtai_taskq.h Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2008-2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTAI_TASKQ_H
#define _RTAI_TASKQ_H
#include <rtai_schedcore.h>
extern struct epoch_struct boot_epoch;
typedef struct rt_task_queue {
struct rt_queue queue; /* <= Must be first in struct. */
int qtype;
} TASKQ;
#define XNTIMEO 0x00000001 // RTE_TIMOUT
#define XNRMID 0x00000002 // RTE_OBJREM
#define XNBREAK 0x00000004 // RTE_UNBLKD
#define TASKQ_PRIO 0x0
#define TASKQ_FIFO 0x1
#define RT_SCHED_TASKQ RT_SCHED_SEMAPHORE
#ifdef CONFIG_SMP
extern volatile unsigned long tosched_mask;
#define TOSCHED_TASK(task) \
do { tosched_mask |= (1 << (task)->runnable_on_cpus); } while (0)
#else /* !CONFIG_SMP */
#define TOSCHED_TASK(task)
#endif /* CONFIG_SMP */
void rt_schedule_readied(void);
void rt_taskq_init(TASKQ *taskq, unsigned long type);
RT_TASK *rt_taskq_ready_one(TASKQ *taskq);
int rt_taskq_ready_all(TASKQ *taskq, unsigned long why);
void rt_taskq_wait(TASKQ *taskq);
void rt_taskq_wait_until(TASKQ *taskq, RTIME time);
#define rt_taskq_delete(taskq) rt_taskq_ready_all(taskq, RTE_OBJREM)
#define rt_taskq_wait_timed(taskq, delay) \
do { rt_taskq_wait_until(taskq, get_time() + delay); } while (0)
static inline int rt_task_test_taskq_retval(RT_TASK *task, unsigned long mask)
{
return ((task)->retval & mask);
}
#endif /* !_RTAI_TASKQ_H */

571
addons/rtdm/rtdm.h Normal file
View file

@ -0,0 +1,571 @@
/**
* @file
* Real-Time Driver Model for RTAI, user API header
*
* @note Copyright (C) 2005, 2006 Jan Kiszka <jan.kiszka@web.de>
* @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>
* @note Copyright (C) 2005-2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @ingroup userapi
*/
/*!
* @defgroup rtdm Real-Time Driver Model
*
* The Real-Time Driver Model (RTDM) provides a unified interface to
* both users and developers of real-time device
* drivers. Specifically, it addresses the constraints of mixed
* RT/non-RT systems like RTAI. RTDM conforms to POSIX
* semantics (IEEE Std 1003.1) where available and applicable.
*
* @b API @b Revision: 8
*/
/*!
* @ingroup rtdm
* @defgroup userapi User API
*
* This is the upper interface of RTDM provided to application programs both
* in kernel and user space. Note that certain functions may not be
* implemented by every device. Refer to the @ref profiles "Device Profiles"
* for precise information.
*/
#ifndef _RTDM_H
#define _RTDM_H
#define RTDM_INDX 15
#define __rtdm_fdcount 0
#define __rtdm_open 1
#define __rtdm_socket 2
#define __rtdm_close 3
#define __rtdm_ioctl 4
#define __rtdm_read 5
#define __rtdm_write 6
#define __rtdm_recvmsg 7
#define __rtdm_sendmsg 8
#define __rtdm_select 9
#ifdef __KERNEL__
#include <linux/fcntl.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/socket.h>
typedef u32 socklen_t;
typedef struct task_struct rtdm_user_info_t;
#else /* !__KERNEL__ */
#include <fcntl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#endif /* !__KERNEL__ */
/*!
* @addtogroup rtdm
* @{
*/
/*!
* @anchor api_versioning @name API Versioning
* @{ */
/** Common user and driver API version */
#define RTDM_API_VER 8
/** Minimum API revision compatible with the current release */
#define RTDM_API_MIN_COMPAT_VER 6
/** @} API Versioning */
/** RTDM type for representing absolute dates. Its base type is a 64 bit
* unsigned integer. The unit is 1 nanosecond. */
typedef int64_t nanosecs_abs_t;
/** RTDM type for representing relative intervals. Its base type is a 64 bit
* signed integer. The unit is 1 nanosecond. Relative intervals can also
* encode the special timeouts "infinite" and "non-blocking", see
* @ref RTDM_TIMEOUT_xxx. */
typedef int64_t nanosecs_rel_t;
/*!
* @anchor RTDM_TIMEOUT_xxx @name RTDM_TIMEOUT_xxx
* Special timeout values
* @{ */
/** Block forever. */
#define RTDM_TIMEOUT_INFINITE 0
/** Any negative timeout means non-blocking. */
#define RTDM_TIMEOUT_NONE (-1)
/** @} RTDM_TIMEOUT_xxx */
/** @} rtdm */
/*!
* @addtogroup profiles
* @{
*/
/*!
* @anchor RTDM_CLASS_xxx @name RTDM_CLASS_xxx
* Device classes
* @{ */
#define RTDM_CLASS_PARPORT 1
#define RTDM_CLASS_SERIAL 2
#define RTDM_CLASS_CAN 3
#define RTDM_CLASS_NETWORK 4
#define RTDM_CLASS_RTMAC 5
#define RTDM_CLASS_TESTING 6
#define RTDM_CLASS_RTIPC 7
/*
#define RTDM_CLASS_USB ?
#define RTDM_CLASS_FIREWIRE ?
#define RTDM_CLASS_INTERBUS ?
#define RTDM_CLASS_PROFIBUS ?
#define ...
*/
#define RTDM_CLASS_EXPERIMENTAL 224
#define RTDM_CLASS_MAX 255
/** @} RTDM_CLASS_xxx */
#define RTDM_SUBCLASS_GENERIC (-1)
#define RTIOC_TYPE_COMMON 0
/*!
* @anchor device_naming @name Device Naming
* Maximum length of device names (excluding the final null character)
* @{
*/
#define RTDM_MAX_DEVNAME_LEN 31
/** @} Device Naming */
/**
* Device information
*/
typedef struct rtdm_device_info {
/** Device flags, see @ref dev_flags "Device Flags" for details */
int device_flags;
/** Device class ID, see @ref RTDM_CLASS_xxx */
int device_class;
/** Device sub-class, either RTDM_SUBCLASS_GENERIC or a
* RTDM_SUBCLASS_xxx definition of the related @ref profiles
* "Device Profile" */
int device_sub_class;
/** Supported device profile version */
int profile_version;
} rtdm_device_info_t;
/*!
* @anchor RTDM_PURGE_xxx_BUFFER @name RTDM_PURGE_xxx_BUFFER
* Flags selecting buffers to be purged
* @{ */
#define RTDM_PURGE_RX_BUFFER 0x0001
#define RTDM_PURGE_TX_BUFFER 0x0002
/** @} RTDM_PURGE_xxx_BUFFER*/
/*!
* @anchor common_IOCTLs @name Common IOCTLs
* The following IOCTLs are common to all device profiles.
* @{
*/
/**
* Retrieve information about a device or socket.
* @param[out] arg Pointer to information buffer (struct rtdm_device_info)
*/
#define RTIOC_DEVICE_INFO \
_IOR(RTIOC_TYPE_COMMON, 0x00, struct rtdm_device_info)
/**
* Purge internal device or socket buffers.
* @param[in] arg Purge mask, see @ref RTDM_PURGE_xxx_BUFFER
*/
#define RTIOC_PURGE _IOW(RTIOC_TYPE_COMMON, 0x10, int)
/** @} Common IOCTLs */
/** @} rtdm */
/* Internally used for mapping socket functions on IOCTLs */
struct _rtdm_getsockopt_args {
int level;
int optname;
void *optval;
socklen_t *optlen;
};
struct _rtdm_setsockopt_args {
int level;
int optname;
const void *optval;
socklen_t optlen;
};
struct _rtdm_getsockaddr_args {
struct sockaddr *addr;
socklen_t *addrlen;
};
struct _rtdm_setsockaddr_args {
const struct sockaddr *addr;
socklen_t addrlen;
};
#define _RTIOC_GETSOCKOPT _IOW(RTIOC_TYPE_COMMON, 0x20, \
struct _rtdm_getsockopt_args)
#define _RTIOC_SETSOCKOPT _IOW(RTIOC_TYPE_COMMON, 0x21, \
struct _rtdm_setsockopt_args)
#define _RTIOC_BIND _IOW(RTIOC_TYPE_COMMON, 0x22, \
struct _rtdm_setsockaddr_args)
#define _RTIOC_CONNECT _IOW(RTIOC_TYPE_COMMON, 0x23, \
struct _rtdm_setsockaddr_args)
#define _RTIOC_LISTEN _IOW(RTIOC_TYPE_COMMON, 0x24, \
int)
#define _RTIOC_ACCEPT _IOW(RTIOC_TYPE_COMMON, 0x25, \
struct _rtdm_getsockaddr_args)
#define _RTIOC_GETSOCKNAME _IOW(RTIOC_TYPE_COMMON, 0x26, \
struct _rtdm_getsockaddr_args)
#define _RTIOC_GETPEERNAME _IOW(RTIOC_TYPE_COMMON, 0x27, \
struct _rtdm_getsockaddr_args)
#define _RTIOC_SHUTDOWN _IOW(RTIOC_TYPE_COMMON, 0x28, \
int)
#ifdef __KERNEL__
int __rt_dev_open(rtdm_user_info_t *user_info, const char *path, int oflag);
int __rt_dev_socket(rtdm_user_info_t *user_info, int protocol_family,
int socket_type, int protocol);
int __rt_dev_close(rtdm_user_info_t *user_info, int fd);
int __rt_dev_ioctl(rtdm_user_info_t *user_info, int fd, int request, ...);
ssize_t __rt_dev_read(rtdm_user_info_t *user_info, int fd, void *buf,
size_t nbyte);
ssize_t __rt_dev_write(rtdm_user_info_t *user_info, int fd, const void *buf,
size_t nbyte);
ssize_t __rt_dev_recvmsg(rtdm_user_info_t *user_info, int fd,
struct msghdr *msg, int flags);
ssize_t __rt_dev_sendmsg(rtdm_user_info_t *user_info, int fd,
const struct msghdr *msg, int flags);
#include "select.h"
int __rt_dev_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, nanosecs_rel_t timeout, struct xnselector *selector, int space);
#endif /* __KERNEL__ */
/* Define RTDM_NO_DEFAULT_USER_API to switch off the default rt_dev_xxx
* interface when providing a customised user API */
#ifndef RTDM_NO_DEFAULT_USER_API
#ifdef __KERNEL__
#define rt_dev_open(path, oflag, ...) \
__rt_dev_open(NULL, path, oflag)
#define rt_dev_socket(protocol_family, socket_type, protocol) \
__rt_dev_socket(NULL, protocol_family, socket_type, protocol)
#define rt_dev_close(fd) \
__rt_dev_close(NULL, fd)
#define rt_dev_ioctl(fd, request, ...) \
__rt_dev_ioctl(NULL, fd, request, __VA_ARGS__)
#define rt_dev_read(fd, buf, nbyte) \
__rt_dev_read(NULL, fd, buf, nbyte)
#define rt_dev_write(fd, buf, nbyte) \
__rt_dev_write(NULL, fd, buf, nbyte)
#define rt_dev_recvmsg(fd, msg, flags) \
__rt_dev_recvmsg(NULL, fd, msg, flags)
#define rt_dev_sendmsg(fd, msg, flags) \
__rt_dev_sendmsg(NULL, fd, msg, flags)
static inline ssize_t rt_dev_recvfrom(int fd, void *buf, size_t len, int flags,
struct sockaddr *from,
socklen_t *fromlen)
{
struct iovec iov;
struct msghdr msg;
int ret;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_name = from;
msg.msg_namelen = from ? *fromlen : 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = rt_dev_recvmsg(fd, &msg, flags);
if (ret >= 0 && from)
*fromlen = msg.msg_namelen;
return ret;
}
static inline int rt_dev_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, nanosecs_rel_t timeout)
{
#ifdef CONFIG_RTAI_RTDM_SELECT
struct xnselector *selector;
int ret;
selector = rt_malloc(sizeof(struct xnselector));
xnselector_init(selector);
ret = __rt_dev_select(nfds, rfds, wfds, efds, timeout, selector, 1);
xnselector_destroy(selector);
return ret;
#else
return -ENOSYS;
#endif
}
#else /* !__KERNEL__ */
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _RTAI_FUSION_LXRT_H
#include <rtai_lxrt.h>
#endif
#include <stdarg.h>
//#define RTAI_LXRT(ext, lsize, srq, arg) rtai_lxrt(ext, lsize, srq, arg).i[LOW]
#ifndef RTDM_RTAI_LXRT
static inline int RTDM_RTAI_LXRT(int ext, int lsize, int srq, void *arg)
{
int r;
if ((r = rtai_lxrt(ext, lsize, srq, arg).i[LOW]) == -ENOSYS && rt_is_hard_real_time(NULL)) {
rt_make_soft_real_time();
r = rtai_lxrt(ext, lsize, srq, arg).i[LOW];
rt_make_hard_real_time();
}
return r;
}
#endif
static inline int rt_dev_fdcount(void)
{
struct { long dummy; } arg = { 0 };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_fdcount, &arg);
}
static inline int rt_dev_open(const char *path, int oflag, ...)
{
struct { const char *path; long oflag; } arg = { path, oflag };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_open, &arg);
}
static inline int rt_dev_socket(int protocol_family, int socket_type, int protocol)
{
struct { long protocol_family; long socket_type; long protocol; } arg = { protocol_family, socket_type, protocol };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_socket, &arg);
}
static inline int rt_dev_close(int fd)
{
struct { long fd; } arg = { fd };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_close, &arg);
}
static inline int rt_dev_ioctl(int fd, int request, ...)
{
struct { long fd; long request; void *arg; } arg = { fd, request, NULL };
va_list ap;
va_start(ap, request);
arg.arg = va_arg(ap, void *);
va_end(ap);
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_ioctl, &arg);
}
static inline ssize_t rt_dev_read(int fd, void *buf, size_t nbytes)
{
struct { long fd; void *buf; long nbytes; } arg = { fd, buf, nbytes };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_read, &arg);
}
static inline ssize_t rt_dev_write(int fd, const void *buf, size_t nbytes)
{
struct { long fd; const void *buf; long nbytes; } arg = { fd, buf, nbytes };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_write, &arg);
}
static inline ssize_t rt_dev_recvmsg(int fd, struct msghdr *msg, int flags)
{
struct { long fd; struct msghdr *msg; long flags; } arg = { fd, msg, flags };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_recvmsg, &arg);
}
static inline ssize_t rt_dev_sendmsg(int fd, const struct msghdr *msg, int flags)
{
struct { long fd; const struct msghdr *msg; long flags; } arg = { fd, msg, flags };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_sendmsg, &arg);
}
static inline ssize_t rt_dev_recvfrom(int fd, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
struct iovec iov;
struct msghdr msg;
int ret;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_name = from;
msg.msg_namelen = from ? *fromlen : 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = rt_dev_recvmsg(fd, &msg, flags);
if (ret >= 0 && from)
*fromlen = msg.msg_namelen;
return ret;
}
static inline int rt_dev_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, nanosecs_rel_t timeout)
{
#ifdef CONFIG_RTAI_RTDM_SELECT
struct { long nfds; fd_set *rfds; fd_set *wfds; fd_set *efds; nanosecs_rel_t timeout; } arg = { nfds, rfds, wfds, efds, timeout };
return RTDM_RTAI_LXRT(RTDM_INDX, SIZARG, __rtdm_select, &arg);
#else
return -ENOSYS;
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* !__KERNEL__ */
#ifdef __cplusplus
extern "C" {
#endif
static inline ssize_t rt_dev_recv(int fd, void *buf, size_t len, int flags)
{
return rt_dev_recvfrom(fd, buf, len, flags, NULL, NULL);
}
static inline ssize_t rt_dev_sendto(int fd, const void *buf, size_t len,
int flags, const struct sockaddr *to,
socklen_t tolen)
{
struct iovec iov;
struct msghdr msg;
iov.iov_base = (void *)buf;
iov.iov_len = len;
msg.msg_name = (struct sockaddr *)to;
msg.msg_namelen = tolen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
return rt_dev_sendmsg(fd, &msg, flags);
}
static inline ssize_t rt_dev_send(int fd, const void *buf, size_t len,
int flags)
{
return rt_dev_sendto(fd, buf, len, flags, NULL, 0);
}
static inline int rt_dev_getsockopt(int fd, int level, int optname,
void *optval, socklen_t *optlen)
{
struct _rtdm_getsockopt_args args =
{ level, optname, optval, optlen };
return rt_dev_ioctl(fd, _RTIOC_GETSOCKOPT, &args);
}
static inline int rt_dev_setsockopt(int fd, int level, int optname,
const void *optval, socklen_t optlen)
{
struct _rtdm_setsockopt_args args =
{ level, optname, (void *)optval, optlen };
return rt_dev_ioctl(fd, _RTIOC_SETSOCKOPT, &args);
}
static inline int rt_dev_bind(int fd, const struct sockaddr *my_addr,
socklen_t addrlen)
{
struct _rtdm_setsockaddr_args args = { my_addr, addrlen };
return rt_dev_ioctl(fd, _RTIOC_BIND, &args);
}
static inline int rt_dev_connect(int fd, const struct sockaddr *serv_addr,
socklen_t addrlen)
{
struct _rtdm_setsockaddr_args args = { serv_addr, addrlen };
return rt_dev_ioctl(fd, _RTIOC_CONNECT, &args);
}
static inline int rt_dev_listen(int fd, int backlog)
{
return rt_dev_ioctl(fd, _RTIOC_LISTEN, backlog);
}
static inline int rt_dev_accept(int fd, struct sockaddr *addr,
socklen_t *addrlen)
{
struct _rtdm_getsockaddr_args args = { addr, addrlen };
return rt_dev_ioctl(fd, _RTIOC_ACCEPT, &args);
}
static inline int rt_dev_getsockname(int fd, struct sockaddr *name,
socklen_t *namelen)
{
struct _rtdm_getsockaddr_args args = { name, namelen };
return rt_dev_ioctl(fd, _RTIOC_GETSOCKNAME, &args);
}
static inline int rt_dev_getpeername(int fd, struct sockaddr *name,
socklen_t *namelen)
{
struct _rtdm_getsockaddr_args args = { name, namelen };
return rt_dev_ioctl(fd, _RTIOC_GETPEERNAME, &args);
}
static inline int rt_dev_shutdown(int fd, int how)
{
return rt_dev_ioctl(fd, _RTIOC_SHUTDOWN, how);
}
#ifdef __cplusplus
}
#endif
#endif /* RTDM_NO_DEFAULT_USER_API */
#endif /* _RTDM_H */

1373
addons/rtdm/rtdm_driver.h Normal file

File diff suppressed because it is too large Load diff

522
addons/rtdm/rtserial.h Normal file
View file

@ -0,0 +1,522 @@
/**
* @file
* Real-Time Driver Model for RTAI, serial device profile header
*
* @note Copyright (C) 2005-2007 Jan Kiszka <jan.kiszka@web.de>
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @ingroup rtserial
*/
/*!
* @ingroup profiles
* @defgroup rtserial Serial Devices
*
* This is the common interface a RTDM-compliant serial device has to provide.
* Feel free to comment on this profile via the RTAI mailing list
* (rtai@rtai.org) or directly to the author (jan.kiszka@web.de).
*
* @b Profile @b Revision: 3
* @n
* @n
* @par Device Characteristics
* @ref rtdm_device.device_flags "Device Flags": @c RTDM_NAMED_DEVICE, @c RTDM_EXCLUSIVE @n
* @n
* @ref rtdm_device.device_name "Device Name": @c "rtser<N>", N >= 0 @n
* @n
* @ref rtdm_device.device_class "Device Class": @c RTDM_CLASS_SERIAL @n
* @n
*
* @par Supported Operations
* @b Open @n
* Environments: non-RT (RT optional, deprecated)@n
* Specific return values: none @n
* @n
* @b Close @n
* Environments: non-RT (RT optional, deprecated)@n
* Specific return values: none @n
* @n
* @b IOCTL @n
* Mandatory Environments: see @ref SERIOCTLs "below" @n
* Specific return values: see @ref SERIOCTLs "below" @n
* @n
* @b Read @n
* Environments: RT (non-RT optional)@n
* Specific return values:
* - -ETIMEDOUT
* - -EINTR (interrupted explicitly or by signal)
* - -EAGAIN (no data available in non-blocking mode)
* - -EBADF (device has been closed while reading)
* - -EIO (hardware error or broken bit stream)
* .
* @n
* @b Write @n
* Environments: RT (non-RT optional)@n
* Specific return values:
* - -ETIMEDOUT
* - -EINTR (interrupted explicitly or by signal)
* - -EAGAIN (no data written in non-blocking mode)
* - -EBADF (device has been closed while writing)
*
* @{
*/
#ifndef _RTSERIAL_H
#define _RTSERIAL_H
#include <rtdm/rtdm.h>
#define RTSER_PROFILE_VER 3
/*!
* @anchor RTSER_DEF_BAUD @name RTSER_DEF_BAUD
* Default baud rate
* @{ */
#define RTSER_DEF_BAUD 9600
/** @} */
/*!
* @anchor RTSER_xxx_PARITY @name RTSER_xxx_PARITY
* Number of parity bits
* @{ */
#define RTSER_NO_PARITY 0x00
#define RTSER_ODD_PARITY 0x01
#define RTSER_EVEN_PARITY 0x03
#define RTSER_DEF_PARITY RTSER_NO_PARITY
/** @} */
/*!
* @anchor RTSER_xxx_BITS @name RTSER_xxx_BITS
* Number of data bits
* @{ */
#define RTSER_5_BITS 0x00
#define RTSER_6_BITS 0x01
#define RTSER_7_BITS 0x02
#define RTSER_8_BITS 0x03
#define RTSER_DEF_BITS RTSER_8_BITS
/** @} */
/*!
* @anchor RTSER_xxx_STOPB @name RTSER_xxx_STOPB
* Number of stop bits
* @{ */
#define RTSER_1_STOPB 0x00
/** valid only in combination with 5 data bits */
#define RTSER_1_5_STOPB 0x01
#define RTSER_2_STOPB 0x01
#define RTSER_DEF_STOPB RTSER_1_STOPB
/** @} */
/*!
* @anchor RTSER_xxx_HAND @name RTSER_xxx_HAND
* Handshake mechanisms
* @{ */
#define RTSER_NO_HAND 0x00
#define RTSER_RTSCTS_HAND 0x01
#define RTSER_DEF_HAND RTSER_NO_HAND
/** @} */
/*!
* @anchor RTSER_RS485_xxx @name RTSER_RS485_xxx
* RS485 mode with automatic RTS handling
* @{ */
#define RTSER_RS485_DISABLE 0x00
#define RTSER_RS485_ENABLE 0x01
#define RTSER_DEF_RS485 RTSER_RS485_DISABLE
/** @} */
/*!
* @anchor RTSER_FIFO_xxx @name RTSER_FIFO_xxx
* Reception FIFO interrupt threshold
* @{ */
#define RTSER_FIFO_DEPTH_1 0x00
#define RTSER_FIFO_DEPTH_4 0x40
#define RTSER_FIFO_DEPTH_8 0x80
#define RTSER_FIFO_DEPTH_14 0xC0
#define RTSER_DEF_FIFO_DEPTH RTSER_FIFO_DEPTH_1
/** @} */
/*!
* @anchor RTSER_TIMEOUT_xxx @name RTSER_TIMEOUT_xxx
* Special timeout values, see also @ref RTDM_TIMEOUT_xxx
* @{ */
#define RTSER_TIMEOUT_INFINITE RTDM_TIMEOUT_INFINITE
#define RTSER_TIMEOUT_NONE RTDM_TIMEOUT_NONE
#define RTSER_DEF_TIMEOUT RTDM_TIMEOUT_INFINITE
/** @} */
/*!
* @anchor RTSER_xxx_TIMESTAMP_HISTORY @name RTSER_xxx_TIMESTAMP_HISTORY
* Timestamp history control
* @{ */
#define RTSER_RX_TIMESTAMP_HISTORY 0x01
#define RTSER_DEF_TIMESTAMP_HISTORY 0x00
/** @} */
/*!
* @anchor RTSER_EVENT_xxx @name RTSER_EVENT_xxx
* Events bits
* @{ */
#define RTSER_EVENT_RXPEND 0x01
#define RTSER_EVENT_ERRPEND 0x02
#define RTSER_EVENT_MODEMHI 0x04
#define RTSER_EVENT_MODEMLO 0x08
#define RTSER_EVENT_TXEMPTY 0x10
#define RTSER_DEF_EVENT_MASK 0x00
/** @} */
/*!
* @anchor RTSER_SET_xxx @name RTSER_SET_xxx
* Configuration mask bits
* @{ */
#define RTSER_SET_BAUD 0x0001
#define RTSER_SET_PARITY 0x0002
#define RTSER_SET_DATA_BITS 0x0004
#define RTSER_SET_STOP_BITS 0x0008
#define RTSER_SET_HANDSHAKE 0x0010
#define RTSER_SET_FIFO_DEPTH 0x0020
#define RTSER_SET_TIMEOUT_RX 0x0100
#define RTSER_SET_TIMEOUT_TX 0x0200
#define RTSER_SET_TIMEOUT_EVENT 0x0400
#define RTSER_SET_TIMESTAMP_HISTORY 0x0800
#define RTSER_SET_EVENT_MASK 0x1000
#define RTSER_SET_RS485 0x2000
/** @} */
/*!
* @anchor RTSER_LSR_xxx @name RTSER_LSR_xxx
* Line status bits
* @{ */
#define RTSER_LSR_DATA 0x01
#define RTSER_LSR_OVERRUN_ERR 0x02
#define RTSER_LSR_PARITY_ERR 0x04
#define RTSER_LSR_FRAMING_ERR 0x08
#define RTSER_LSR_BREAK_IND 0x10
#define RTSER_LSR_THR_EMTPY 0x20
#define RTSER_LSR_TRANSM_EMPTY 0x40
#define RTSER_LSR_FIFO_ERR 0x80
#define RTSER_SOFT_OVERRUN_ERR 0x0100
/** @} */
/*!
* @anchor RTSER_MSR_xxx @name RTSER_MSR_xxx
* Modem status bits
* @{ */
#define RTSER_MSR_DCTS 0x01
#define RTSER_MSR_DDSR 0x02
#define RTSER_MSR_TERI 0x04
#define RTSER_MSR_DDCD 0x08
#define RTSER_MSR_CTS 0x10
#define RTSER_MSR_DSR 0x20
#define RTSER_MSR_RI 0x40
#define RTSER_MSR_DCD 0x80
/** @} */
/*!
* @anchor RTSER_MCR_xxx @name RTSER_MCR_xxx
* Modem control bits
* @{ */
#define RTSER_MCR_DTR 0x01
#define RTSER_MCR_RTS 0x02
#define RTSER_MCR_OUT1 0x04
#define RTSER_MCR_OUT2 0x08
#define RTSER_MCR_LOOP 0x10
/** @} */
/*!
* @anchor RTSER_BREAK_xxx @name RTSER_BREAK_xxx
* Break control
* @{ */
#define RTSER_BREAK_CLR 0x00
#define RTSER_BREAK_SET 0x01
/**
* Serial device configuration
*/
typedef struct rtser_config {
/** mask specifying valid fields, see @ref RTSER_SET_xxx */
int config_mask;
/** baud rate, default @ref RTSER_DEF_BAUD */
int baud_rate;
/** number of parity bits, see @ref RTSER_xxx_PARITY */
int parity;
/** number of data bits, see @ref RTSER_xxx_BITS */
int data_bits;
/** number of stop bits, see @ref RTSER_xxx_STOPB */
int stop_bits;
/** handshake mechanisms, see @ref RTSER_xxx_HAND */
int handshake;
/** reception FIFO interrupt threshold, see @ref RTSER_FIFO_xxx */
int fifo_depth;
int reserved;
/** reception timeout, see @ref RTSER_TIMEOUT_xxx for special
* values */
nanosecs_rel_t rx_timeout;
/** transmission timeout, see @ref RTSER_TIMEOUT_xxx for special
* values */
nanosecs_rel_t tx_timeout;
/** event timeout, see @ref RTSER_TIMEOUT_xxx for special values */
nanosecs_rel_t event_timeout;
/** enable timestamp history, see @ref RTSER_xxx_TIMESTAMP_HISTORY */
int timestamp_history;
/** event mask to be used with @ref RTSER_RTIOC_WAIT_EVENT, see
* @ref RTSER_EVENT_xxx */
int event_mask;
/** enable RS485 mode, see @ref RTSER_RS485_xxx */
int rs485;
} rtser_config_t;
/**
* Serial device status
*/
typedef struct rtser_status {
/** line status register, see @ref RTSER_LSR_xxx */
int line_status;
/** modem status register, see @ref RTSER_MSR_xxx */
int modem_status;
} rtser_status_t;
/**
* Additional information about serial device events
*/
typedef struct rtser_event {
/** signalled events, see @ref RTSER_EVENT_xxx */
int events;
/** number of pending input characters */
int rx_pending;
/** last interrupt timestamp */
nanosecs_abs_t last_timestamp;
/** reception timestamp of oldest character in input queue */
nanosecs_abs_t rxpend_timestamp;
} rtser_event_t;
#define RTIOC_TYPE_SERIAL RTDM_CLASS_SERIAL
/*!
* @name Sub-Classes of RTDM_CLASS_SERIAL
* @{ */
#define RTDM_SUBCLASS_16550A 0
/** @} */
/*!
* @anchor SERIOCTLs @name IOCTLs
* Serial device IOCTLs
* @{ */
/**
* Get serial device configuration
*
* @param[out] arg Pointer to configuration buffer (struct rtser_config)
*
* @return 0 on success, otherwise negative error code
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_GET_CONFIG \
_IOR(RTIOC_TYPE_SERIAL, 0x00, struct rtser_config)
/**
* Set serial device configuration
*
* @param[in] arg Pointer to configuration buffer (struct rtser_config)
*
* @return 0 on success, otherwise:
*
* - -EPERM is returned if the caller's context is invalid, see note below.
*
* - -ENOMEM is returned if a new history buffer for timestamps cannot be
* allocated.
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* @note If rtser_config contains a valid timestamp_history and the
* addressed device has been opened in non-real-time context, this IOCTL must
* be issued in non-real-time context as well. Otherwise, this command will
* fail.
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_SET_CONFIG \
_IOW(RTIOC_TYPE_SERIAL, 0x01, struct rtser_config)
/**
* Get serial device status
*
* @param[out] arg Pointer to status buffer (struct rtser_status)
*
* @return 0 on success, otherwise negative error code
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* @note The error states @c RTSER_LSR_OVERRUN_ERR, @c RTSER_LSR_PARITY_ERR,
* @c RTSER_LSR_FRAMING_ERR, and @c RTSER_SOFT_OVERRUN_ERR that may have
* occured during previous read accesses to the device will be saved for being
* reported via this IOCTL. Upon return from @c RTSER_RTIOC_GET_STATUS, the
* saved state will be cleared.
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_GET_STATUS \
_IOR(RTIOC_TYPE_SERIAL, 0x02, struct rtser_status)
/**
* Get serial device's modem contol register
*
* @param[out] arg Pointer to variable receiving the content (int, see
* @ref RTSER_MCR_xxx)
*
* @return 0 on success, otherwise negative error code
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_GET_CONTROL \
_IOR(RTIOC_TYPE_SERIAL, 0x03, int)
/**
* Set serial device's modem contol register
*
* @param[in] arg New control register content (int, see @ref RTSER_MCR_xxx)
*
* @return 0 on success, otherwise negative error code
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_SET_CONTROL \
_IOW(RTIOC_TYPE_SERIAL, 0x04, int)
/**
* Wait on serial device events according to previously set mask
*
* @param[out] arg Pointer to event information buffer (struct rtser_event)
*
* @return 0 on success, otherwise:
*
* - -EBUSY is returned if another task is already waiting on events of this
* device.
*
* - -EBADF is returned if the file descriptor is invalid or the device has
* just been closed.
*
* Environments:
*
* This service can be called from:
*
* - Kernel-based task
* - User-space task (RT)
*
* Rescheduling: possible.
*/
#define RTSER_RTIOC_WAIT_EVENT \
_IOR(RTIOC_TYPE_SERIAL, 0x05, struct rtser_event)
/** @} */
/**
* Set or clear break on UART output line
*
* @param[in] arg @c RTSER_BREAK_SET or @c RTSER_BREAK_CLR (int)
*
* @return 0 on success, otherwise negative error code
*
* Environments:
*
* This service can be called from:
*
* - Kernel module initialization/cleanup code
* - Kernel-based task
* - User-space task (RT, non-RT)
*
* @note A set break condition may also be cleared on UART line
* reconfiguration.
*
* Rescheduling: never.
*/
#define RTSER_RTIOC_BREAK_CTL \
_IOR(RTIOC_TYPE_SERIAL, 0x06, int)
/** @} */
/*!
* @anchor SERutils @name RT Serial example and utility programs
* @{ */
/** @example cross-link.c */
/** @} */
/** @} */
#endif /* _RTSERIAL_H */

466
addons/rtdm/select.c Normal file
View file

@ -0,0 +1,466 @@
/*!\file select.c
* \brief file descriptors events multiplexing.
* \author Gilles Chanteperdrix
*
* Copyright (C) 2008 Efixo <gilles.chanteperdrix@laposte.net>
*
* with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* RTAI 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.
*
* RTAI 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 RTAI; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* \ingroup select
*/
/*!
* \ingroup nucleus
* \defgroup select File descriptors events multiplexing services.
*
* File descriptors events multiplexing services.
*
* This module implements the services needed for implementing the posix
* "select" service, or any other events multiplexing services.
*
* Following the implementation of the posix select service, this module defines
* three types of events:
* - \a XNSELECT_READ meaning that a file descriptor is ready for reading;
* - \a XNSELECT_WRITE meaning that a file descriptor is ready for writing;
* - \a XNSELECT_EXCEPT meaning that a file descriptor received an exceptional
* event.
*
* It works by defining two structures:
* - a @a struct @a xnselect structure, which should be added to every file
* descriptor for every event type (read, write, or except);
* - a @a struct @a xnselector structure, the selection structure, passed by
* the thread calling the xnselect service, where this service does all its
* housekeeping.
*@{*/
#include "select.h"
#ifdef CONFIG_RTAI_RTDM_SELECT
#include <linux/types.h>
#include <linux/bitops.h> /* For hweight_long */
static xnqueue_t xnselectors;
static int xnselect_apc;
#define link2binding(baddr, memb) \
container_of(baddr, struct xnselect_binding, memb)
/**
* Initialize a @a struct @a xnselect structure.
*
* This service must be called to initialize a @a struct @a xnselect structure
* before it is bound to a selector by the means of xnselect_bind().
*
* @param select_block pointer to the xnselect structure to be initialized
*/
void xnselect_init(struct xnselect *select_block)
{
initq(&select_block->bindings);
}
EXPORT_SYMBOL_GPL(xnselect_init);
static inline int xnselect_wakeup(struct xnselector *selector)
{
return xnsynch_flush(&selector->synchbase, 0) == XNSYNCH_RESCHED;
}
/**
* Bind a file descriptor (represented by its @a xnselect structure) to a
* selector block.
*
* @param select_block pointer to the @a struct @a xnselect to be bound;
*
* @param binding pointer to a newly allocated (using xnmalloc) @a struct
* @a xnselect_binding;
*
* @param selector pointer to the selector structure;
*
* @param type type of events (@a XNSELECT_READ, @a XNSELECT_WRITE, or @a
* XNSELECT_EXCEPT);
*
* @param index index of the file descriptor (represented by @a select_block) in the bit fields used by the @a selector structure;
*
* @param state current state of the file descriptor>.
*
* @a select_block must have been initialized with xnselect_init(),
* the @a xnselector structure must have been initialized with
* xnselector_init(), @a binding may be uninitialized.
*
* This service must be called with nklock locked, irqs off. For this reason,
* the @a binding parameter must have been allocated by the caller outside the
* locking section.
*
* @retval -EINVAL if @a type or @a index is invalid;
* @retval 0 otherwise.
*/
int xnselect_bind(struct xnselect *select_block,
struct xnselect_binding *binding,
struct xnselector *selector,
unsigned type,
unsigned index,
unsigned state)
{
if (type >= XNSELECT_MAX_TYPES || index > __FD_SETSIZE)
return -EINVAL;
binding->selector = selector;
binding->fd = select_block;
binding->type = type;
binding->bit_index = index;
inith(&binding->link);
inith(&binding->slink);
appendq(&selector->bindings, &binding->slink);
appendq(&select_block->bindings, &binding->link);
__FD_SET__(index, &selector->fds[type].expected);
if (state) {
__FD_SET__(index, &selector->fds[type].pending);
if (xnselect_wakeup(selector))
xnpod_schedule();
} else
__FD_CLR__(index, &selector->fds[type].pending);
return 0;
}
EXPORT_SYMBOL_GPL(xnselect_bind);
/* Must be called with nklock locked irqs off */
int __xnselect_signal(struct xnselect *select_block, unsigned state)
{
xnholder_t *holder;
int resched;
for(resched = 0, holder = getheadq(&select_block->bindings);
holder; holder = nextq(&select_block->bindings, holder)) {
struct xnselect_binding *binding;
struct xnselector *selector;
binding = link2binding(holder, link);
selector = binding->selector;
if (state) {
if (!__FD_ISSET__(binding->bit_index,
&selector->fds[binding->type].pending)) {
__FD_SET__(binding->bit_index,
&selector->fds[binding->type].pending);
if (xnselect_wakeup(selector))
resched = 1;
}
} else
__FD_CLR__(binding->bit_index,
&selector->fds[binding->type].pending);
}
return resched;
}
EXPORT_SYMBOL_GPL(__xnselect_signal);
/**
* Destroy the @a xnselect structure associated with a file descriptor.
*
* Any binding with a @a xnselector block is destroyed.
*
* @param select_block pointer to the @a xnselect structure associated with a file descriptor
*/
void xnselect_destroy(struct xnselect *select_block)
{
xnholder_t *holder;
int resched = 0;
spl_t s;
xnlock_get_irqsave(&nklock, s);
while ((holder = getq(&select_block->bindings))) {
struct xnselect_binding *binding;
struct xnselector *selector;
binding = link2binding(holder, link);
selector = binding->selector;
__FD_CLR__(binding->bit_index,
&selector->fds[binding->type].expected);
if (!__FD_ISSET__(binding->bit_index,
&selector->fds[binding->type].pending)) {
__FD_SET__(binding->bit_index,
&selector->fds[binding->type].pending);
if (xnselect_wakeup(selector))
resched = 1;
}
removeq(&selector->bindings, &binding->slink);
xnlock_put_irqrestore(&nklock, s);
xnfree(binding);
xnlock_get_irqsave(&nklock, s);
}
if (resched)
xnpod_schedule();
xnlock_put_irqrestore(&nklock, s);
}
EXPORT_SYMBOL_GPL(xnselect_destroy);
static unsigned
fd_set_andnot(fd_set *result, fd_set *first, fd_set *second, unsigned n)
{
unsigned i, not_empty = 0;
for (i = 0; i < __FDELT__(n); i++)
if((result->fds_bits[i] =
first->fds_bits[i] & ~(second->fds_bits[i])))
not_empty = 1;
if (i < __FDSET_LONGS__
&& (result->fds_bits[i] =
first->fds_bits[i] & ~(second->fds_bits[i]) & (__FDMASK__(n) - 1)))
not_empty = 1;
return not_empty;
}
static unsigned
fd_set_and(fd_set *result, fd_set *first, fd_set *second, unsigned n)
{
unsigned i, not_empty = 0;
for (i = 0; i < __FDELT__(n); i++)
if((result->fds_bits[i] =
first->fds_bits[i] & second->fds_bits[i]))
not_empty = 1;
if (i < __FDSET_LONGS__
&& (result->fds_bits[i] =
first->fds_bits[i] & second->fds_bits[i] & (__FDMASK__(n) - 1)))
not_empty = 1;
return not_empty;
}
static void fd_set_zeropad(fd_set *set, unsigned n)
{
unsigned i;
i = __FDELT__(n);
if (i < __FDSET_LONGS__)
set->fds_bits[i] &= (__FDMASK__(n) - 1);
for(i++; i < __FDSET_LONGS__; i++)
set->fds_bits[i] = 0;
}
static unsigned fd_set_popcount(fd_set *set, unsigned n)
{
unsigned count = 0, i;
for (i = 0; i < __FDELT__(n); i++)
if (set->fds_bits[i])
count += hweight_long(set->fds_bits[i]);
if (i < __FDSET_LONGS__ && (set->fds_bits[i] & (__FDMASK__(n) - 1)))
count += hweight_long(set->fds_bits[i] & (__FDMASK__(n) - 1));
return count;
}
/**
* Initialize a selector structure.
*
* @param selector The selector structure to be initialized.
*
* @retval 0
*/
int xnselector_init(struct xnselector *selector)
{
unsigned i;
xnsynch_init(&selector->synchbase, XNSYNCH_FIFO, NULL);
for (i = 0; i < XNSELECT_MAX_TYPES; i++) {
__FD_ZERO__(&selector->fds[i].expected);
__FD_ZERO__(&selector->fds[i].pending);
}
initq(&selector->bindings);
return 0;
}
EXPORT_SYMBOL_GPL(xnselector_init);
/**
* Check the state of a number of file descriptors, wait for a state change if
* no descriptor is ready.
*
* @param selector structure to check for pending events
* @param out_fds The set of descriptors with pending events if a strictly positive number is returned, or the set of descriptors not yet bound if -ECHRNG is returned;
* @param in_fds the set of descriptors which events should be checked
* @param nfds the highest-numbered descriptor in any of the @a in_fds sets, plus 1;
* @param timeout the timeout, whose meaning depends on @a timeout_mode, note
* that xnselect() pass @a timeout and @a timeout_mode unchanged to
* xnsynch_sleep_on, so passing a relative value different from XN_INFINITE as a
* timeout with @a timeout_mode set to XN_RELATIVE, will cause a longer sleep
* than expected if the sleep is interrupted.
* @param timeout_mode the mode of @a timeout.
*
* @retval -EINVAL if @a nfds is negative;
* @retval -ECHRNG if some of the descriptors passed in @a in_fds have not yet
* been registered with xnselect_bind(), @a out_fds contains the set of such
* descriptors;
* @retval -EINTR if @a xnselect was interrupted while waiting;
* @retval 0 in case of timeout.
* @retval the number of file descriptors having received an event.
*/
int xnselect(struct xnselector *selector,
fd_set *out_fds[XNSELECT_MAX_TYPES],
fd_set *in_fds[XNSELECT_MAX_TYPES],
int nfds,
xnticks_t timeout, xntmode_t timeout_mode)
{
unsigned i, not_empty = 0;
xnthread_t *thread;
spl_t s;
if ((unsigned) nfds > __FD_SETSIZE)
return -EINVAL;
thread = xnpod_current_thread();
for (i = 0; i < XNSELECT_MAX_TYPES; i++)
if (out_fds[i])
fd_set_zeropad(out_fds[i], nfds);
xnlock_get_irqsave(&nklock, s);
for (i = 0; i < XNSELECT_MAX_TYPES; i++)
if (out_fds[i]
&& fd_set_andnot(out_fds[i], in_fds[i],
&selector->fds[i].expected, nfds))
not_empty = 1;
xnlock_put_irqrestore(&nklock, s);
if (not_empty)
return -ECHRNG;
xnlock_get_irqsave(&nklock, s);
for (i = 0; i < XNSELECT_MAX_TYPES; i++)
if (out_fds[i]
&& fd_set_and(out_fds[i], in_fds[i],
&selector->fds[i].pending, nfds))
not_empty = 1;
while (!not_empty) {
xnsynch_sleep_on(&selector->synchbase, timeout, timeout_mode);
for (i = 0; i < XNSELECT_MAX_TYPES; i++)
if (out_fds[i]
&& fd_set_and(out_fds[i], in_fds[i],
&selector->fds[i].pending, nfds))
not_empty = 1;
if (xnthread_test_info(thread, XNBREAK | XNTIMEO))
break;
}
xnlock_put_irqrestore(&nklock, s);
if (not_empty) {
unsigned count;
for (count = 0, i = 0; i < XNSELECT_MAX_TYPES; i++)
if (out_fds[i])
count += fd_set_popcount(out_fds[i], nfds);
return count;
}
if (xnthread_test_info(thread, XNBREAK))
return -EINTR;
return 0; /* Timeout */
}
EXPORT_SYMBOL_GPL(xnselect);
/**
* Destroy a selector block.
*
* All bindings with file descriptor are destroyed.
*
* @param selector the selector block to be destroyed
*/
void xnselector_destroy(struct xnselector *selector)
{
spl_t s;
inith(&selector->destroy_link);
xnlock_get_irqsave(&nklock, s);
appendq(&xnselectors, &selector->destroy_link);
xnlock_put_irqrestore(&nklock, s);
rthal_apc_schedule(xnselect_apc);
}
EXPORT_SYMBOL_GPL(xnselector_destroy);
static void xnselector_destroy_loop(void *cookie)
{
struct xnselector *selector;
xnholder_t *holder;
int resched;
spl_t s;
xnlock_get_irqsave(&nklock, s);
while ((holder = getq(&xnselectors))) {
selector = container_of(holder, struct xnselector, destroy_link);
while ((holder = getq(&selector->bindings))) {
struct xnselect_binding *binding;
struct xnselect *fd;
binding = link2binding(holder, slink);
fd = binding->fd;
removeq(&fd->bindings, &binding->link);
xnlock_put_irqrestore(&nklock, s);
xnfree(binding);
xnlock_get_irqsave(&nklock, s);
}
resched =
xnsynch_destroy(&selector->synchbase) == XNSYNCH_RESCHED;
xnlock_put_irqrestore(&nklock, s);
xnfree(selector);
if (resched)
xnpod_schedule();
xnlock_get_irqsave(&nklock, s);
}
xnlock_put_irqrestore(&nklock, s);
}
int xnselect_mount(void)
{
initq(&xnselectors);
xnselect_apc = rthal_apc_alloc("xnselectors_destroy",
xnselector_destroy_loop, NULL);
if (xnselect_apc < 0)
return xnselect_apc;
return 0;
}
int xnselect_umount(void)
{
rthal_apc_free(xnselect_apc);
return 0;
}
#endif
/*@}*/

169
addons/rtdm/select.h Normal file
View file

@ -0,0 +1,169 @@
/*!\file select.h
* \brief file descriptors events multiplexing header.
* \author Gilles Chanteperdrix
*
* Copyright (C) 2008 Efixo <gilles.chanteperdrix@laposte.net>
*
* Rtai 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.
*
* Rtai 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 Rtai; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* \ingroup select
*/
#ifndef XNSELECT_H
#define XNSELECT_H
/*! \addtogroup select
*@{*/
#include "xn.h"
#define XNSELECT_READ 0
#define XNSELECT_WRITE 1
#define XNSELECT_EXCEPT 2
#define XNSELECT_MAX_TYPES 3
struct xnselector {
xnsynch_t synchbase;
struct fds {
fd_set expected;
fd_set pending;
} fds [XNSELECT_MAX_TYPES];
xnholder_t destroy_link;
xnqueue_t bindings; /* only used by xnselector_destroy */
};
#define __NFDBITS__ (8 * sizeof(unsigned long))
#define __FDSET_LONGS__ (__FD_SETSIZE/__NFDBITS__)
#define __FDELT__(d) ((d) / __NFDBITS__)
#define __FDMASK__(d) (1UL << ((d) % __NFDBITS__))
static inline void __FD_SET__(unsigned long __fd, __kernel_fd_set *__fdsetp)
{
unsigned long __tmp = __fd / __NFDBITS__;
unsigned long __rem = __fd % __NFDBITS__;
__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
}
static inline void __FD_CLR__(unsigned long __fd, __kernel_fd_set *__fdsetp)
{
unsigned long __tmp = __fd / __NFDBITS__;
unsigned long __rem = __fd % __NFDBITS__;
__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
}
static inline int __FD_ISSET__(unsigned long __fd, const __kernel_fd_set *__p)
{
unsigned long __tmp = __fd / __NFDBITS__;
unsigned long __rem = __fd % __NFDBITS__;
return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
}
static inline void __FD_ZERO__(__kernel_fd_set *__p)
{
unsigned long *__tmp = __p->fds_bits;
int __i;
__i = __FDSET_LONGS__;
while (__i) {
__i--;
*__tmp = 0;
__tmp++;
}
}
#ifdef CONFIG_RTAI_RTDM_SELECT
struct xnselect {
xnqueue_t bindings;
};
#define DECLARE_XNSELECT(name) struct xnselect name
struct xnselect_binding {
struct xnselector *selector;
struct xnselect *fd;
unsigned type;
unsigned bit_index;
xnholder_t link; /* link in selected fds list. */
xnholder_t slink; /* link in selector list */
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void xnselect_init(struct xnselect *select_block);
int xnselect_bind(struct xnselect *select_block,
struct xnselect_binding *binding,
struct xnselector *selector,
unsigned type,
unsigned bit_index,
unsigned state);
int __xnselect_signal(struct xnselect *select_block, unsigned state);
/**
* Signal a file descriptor state change.
*
* @param select_block pointer to an @a xnselect structure representing the file
* descriptor whose state changed;
* @param state new value of the state.
*
* @retval 1 if rescheduling is needed;
* @retval 0 otherwise.
*/
static inline int
xnselect_signal(struct xnselect *select_block, unsigned state)
{
if (!emptyq_p(&select_block->bindings))
return __xnselect_signal(select_block, state);
return 0;
}
void xnselect_destroy(struct xnselect *select_block);
int xnselector_init(struct xnselector *selector);
int xnselect(struct xnselector *selector,
fd_set *out_fds[XNSELECT_MAX_TYPES],
fd_set *in_fds[XNSELECT_MAX_TYPES],
int nfds,
xnticks_t timeout, xntmode_t timeout_mode);
void xnselector_destroy(struct xnselector *selector);
int xnselect_mount(void);
int xnselect_umount(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#else /* !CONFIG_RTAI_RTDM_SELECT */
struct xnselector;
#define DECLARE_XNSELECT(name)
#define xnselect_init(block)
#define xnselect_bind(select_block,binding,selector,type,bit_index,state) \
({ -EBADF; })
#define xnselect_signal(block, state) ({ int __ret = 0; __ret; })
#define xnselect_destroy(block)
#endif /* !CONFIG_RTAI_RTDM_SELECT */
/*@}*/
#endif /* XNSELECT_H */

651
addons/rtdm/xn.h Normal file
View file

@ -0,0 +1,651 @@
/*
* Copyright (C) 2005-2010 Paolo Mantegazza <mantegazza@aero.polimi.it>
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Wrappers and inlines to avoid too much an editing of RTDM code.
// The core stuff is just RTAI in disguise.
#ifndef _RTAI_XNSTUFF_H
#define _RTAI_XNSTUFF_H
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/mman.h>
#include <rtai_schedcore.h>
#define CONFIG_RTAI_OPT_PERVASIVE
#ifndef CONFIG_RTAI_DEBUG_RTDM
#define CONFIG_RTAI_DEBUG_RTDM 0
#endif
#define RTAI_DEBUG(subsystem) (CONFIG_RTAI_DEBUG_##subsystem > 0)
#define RTAI_ASSERT(subsystem, cond, action) do { \
if (unlikely(CONFIG_RTAI_DEBUG_##subsystem > 0 && !(cond))) { \
xnlogerr("assertion failed at %s:%d (%s)\n", __FILE__, __LINE__, (#cond)); \
action; \
} \
} while(0)
#define RTAI_BUGON(subsystem, cond) do { /*\
if (unlikely(CONFIG_RTAI_DEBUG_##subsystem > 0 && (cond))) \
xnpod_fatal("bug at %s:%d (%s)", __FILE__, __LINE__, (#cond)); */ \
} while(0)
/*
With what above we let some assertion diagnostic. Here below we keep knowledge
of specific assertions we care of.
*/
#define xnpod_root_p() (!current->rtai_tskext(TSKEXT0) || !((RT_TASK *)(current->rtai_tskext(TSKEXT0)))->is_hard)
#define xnshadow_thread(t) ((xnthread_t *)current->rtai_tskext(TSKEXT0))
#define rthal_local_irq_test() (!rtai_save_flags_irqbit())
#define rthal_local_irq_enable rtai_sti
#define rthal_domain rtai_domain
#define rthal_local_irq_disabled() \
({ \
unsigned long __flags, __ret; \
local_irq_save_hw_smp(__flags); \
__ret = ipipe_test_pipeline_from(&rthal_domain); \
local_irq_restore_hw_smp(__flags); \
__ret; \
})
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define _MODULE_PARM_STRING_charp "s"
#define compat_module_param_array(name, type, count, perm) \
static inline void *__check_existence_##name(void) { return &name; } \
MODULE_PARM(name, "1-" __MODULE_STRING(count) _MODULE_PARM_STRING_##type)
typedef unsigned long phys_addr_t;
#else
#define compat_module_param_array(name, type, count, perm) \
module_param_array(name, type, NULL, perm)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
#define trace_mark(ev, fmt, args...) do { } while (0)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
#include <linux/marker.h>
#endif
#define trace_mark(ev, fmt, args...) do { } while (0)
#endif
//recursive smp locks, as for RTAI global lock stuff but with an own name
#define nklock (*((xnlock_t *)rtai_cpu_lock))
#define XNARCH_LOCK_UNLOCKED (xnlock_t) { { 0, 0 } }
typedef unsigned long spl_t;
typedef struct { volatile unsigned long lock[2]; } xnlock_t;
#ifndef list_first_entry
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#endif
#ifndef local_irq_save_hw_smp
#ifdef CONFIG_SMP
#define local_irq_save_hw_smp(flags) local_irq_save_hw(flags)
#define local_irq_restore_hw_smp(flags) local_irq_restore_hw(flags)
#else /* !CONFIG_SMP */
#define local_irq_save_hw_smp(flags) do { (void)(flags); } while (0)
#define local_irq_restore_hw_smp(flags) do { } while (0)
#endif /* !CONFIG_SMP */
#endif /* !local_irq_save_hw_smp */
#ifdef CONFIG_SMP
#define DECLARE_XNLOCK(lock) xnlock_t lock
#define DECLARE_EXTERN_XNLOCK(lock) extern xnlock_t lock
#define DEFINE_XNLOCK(lock) xnlock_t lock = XNARCH_LOCK_UNLOCKED
#define DEFINE_PRIVATE_XNLOCK(lock) static DEFINE_XNLOCK(lock)
static inline void xnlock_init(xnlock_t *lock)
{
*lock = XNARCH_LOCK_UNLOCKED;
}
static inline void xnlock_get(xnlock_t *lock)
{
barrier();
rtai_cli();
if (!test_and_set_bit(hal_processor_id(), &lock->lock[0])) {
rtai_spin_glock(&lock->lock[0]);
}
barrier();
}
static inline void xnlock_put(xnlock_t *lock)
{
barrier();
rtai_cli();
if (test_and_clear_bit(hal_processor_id(), &lock->lock[0])) {
rtai_spin_gunlock(&lock->lock[0]);
}
barrier();
}
static inline spl_t __xnlock_get_irqsave(xnlock_t *lock)
{
unsigned long flags;
barrier();
flags = rtai_save_flags_irqbit_and_cli();
if (!test_and_set_bit(hal_processor_id(), &lock->lock[0])) {
rtai_spin_glock(&lock->lock[0]);
barrier();
return flags | 1;
}
barrier();
return flags;
}
#define xnlock_get_irqsave(lock, flags) \
do { flags = __xnlock_get_irqsave(lock); } while (0)
static inline void xnlock_put_irqrestore(xnlock_t *lock, spl_t flags)
{
barrier();
if (test_and_clear_bit(0, &flags)) {
xnlock_put(lock);
} else {
xnlock_get(lock);
}
if (flags) {
rtai_sti();
}
barrier();
}
#else /* !CONFIG_SMP */
#define DECLARE_XNLOCK(lock)
#define DECLARE_EXTERN_XNLOCK(lock)
#define DEFINE_XNLOCK(lock)
#define DEFINE_PRIVATE_XNLOCK(lock)
#define xnlock_init(lock) do { } while(0)
#define xnlock_get(lock) rtai_cli()
#define xnlock_put(lock) rtai_sti()
#define xnlock_get_irqsave(lock, flags) rtai_save_flags_and_cli(flags)
#define xnlock_put_irqrestore(lock, flags) rtai_restore_flags(flags)
#endif /* CONFIG_SMP */
// memory allocation
#define xnmalloc rt_malloc
#define xnfree rt_free
#define xnarch_fault_range(vma)
// in kernel printing (taken from RTDM pet system)
#define XNARCH_PROMPT "RTDM: "
#define xnprintf(fmt, args...) printk(KERN_INFO XNARCH_PROMPT fmt, ##args)
#define xnlogerr(fmt, args...) printk(KERN_ERR XNARCH_PROMPT fmt, ##args)
#define xnlogwarn xnlogerr
// user space access (taken from Linux)
#define __xn_access_ok(task, type, addr, size) \
(access_ok(type, addr, size))
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define __xn_copy_from_user(task, dstP, srcP, n) \
({ long err = __copy_from_user(dstP, srcP, n); err; })
#define __xn_copy_to_user(task, dstP, srcP, n) \
({ long err = __copy_to_user(dstP, srcP, n); err; })
#else
#define __xn_copy_from_user(task, dstP, srcP, n) \
({ long err = __copy_from_user_inatomic(dstP, srcP, n); err; })
#define __xn_copy_to_user(task, dstP, srcP, n) \
({ long err = __copy_to_user_inatomic(dstP, srcP, n); err; })
#endif
#if !defined CONFIG_M68K || defined CONFIG_MMU
#define __xn_strncpy_from_user(task, dstP, srcP, n) \
({ long err = rt_strncpy_from_user(dstP, srcP, n); err; })
/* ({ long err = __strncpy_from_user(dstP, srcP, n); err; }) */
#else
#define __xn_strncpy_from_user(task, dstP, srcP, n) \
({ long err = strncpy_from_user(dstP, srcP, n); err; })
#endif /* CONFIG_M68K */
static inline int xnarch_remap_io_page_range(struct file *filp, struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
vma->vm_flags |= VM_RESERVED;
return remap_page_range(from, to, size, prot);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
return remap_pfn_range(vma, from, (to) >> PAGE_SHIFT, size, prot);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
return remap_pfn_range(vma, from, (to) >> PAGE_SHIFT, size, prot);
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) */
vma->vm_flags |= VM_RESERVED;
return remap_page_range(vma, from, to, size, prot);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
}
#define wrap_remap_kmem_page_range(vma,from,to,size,prot) ({ \
vma->vm_flags |= VM_RESERVED; \
remap_page_range(from,to,size,prot); \
})
static inline int xnarch_remap_kmem_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
vma->vm_flags |= VM_RESERVED;
return remap_page_range(from, to, size, prot);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) && defined(CONFIG_MMU)
return remap_pfn_range(vma, from, to >> PAGE_SHIFT, size, prot);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
return remap_pfn_range(vma, from, to >> PAGE_SHIFT, size, prot);
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) */
vma->vm_flags |= VM_RESERVED;
return remap_page_range(from, to, size, prot);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
}
#include <rtai_shm.h>
#define __va_to_kva(adr) UVIRT_TO_KVA(adr)
#ifdef CONFIG_MMU
static inline int xnarch_remap_vm_page(struct vm_area_struct *vma, unsigned long from, unsigned long to)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
vma->vm_flags |= VM_RESERVED;
return remap_page_range(from, virt_to_phys((void *)__va_to_kva(to)), PAGE_SIZE, PAGE_SHARED);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
#ifndef VM_RESERVED
#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) && defined(CONFIG_MMU)
vma->vm_flags |= VM_RESERVED;
return vm_insert_page(vma, from, vmalloc_to_page((void *)to));
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
return remap_pfn_range(vma, from, virt_to_phys((void *)__va_to_kva(to)) >> PAGE_SHIFT, PAGE_SHIFT, PAGE_SHARED);
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) */
vma->vm_flags |= VM_RESERVED;
return remap_page_range(from, virt_to_phys((void *)__va_to_kva(to)), PAGE_SIZE, PAGE_SHARED);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
}
#endif
// interrupt setup/management (adopted_&|_adapted from RTDM pet system)
#define RTHAL_NR_IRQS IPIPE_NR_XIRQS
#define XN_ISR_NONE 0x1
#define XN_ISR_HANDLED 0x2
#define XN_ISR_PROPAGATE 0x100
#define XN_ISR_NOENABLE 0x200
#define XN_ISR_BITMASK ~0xff
#define XN_ISR_SHARED 0x1
#define XN_ISR_EDGE 0x2
#define XN_ISR_ATTACHED 0x10000
#if !defined(CONFIG_PPC) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,32) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)))
#define rthal_virtualize_irq(dom, irq, isr, cookie, ackfn, mode) \
ipipe_virtualize_irq(dom, irq, isr, ackfn, mode)
#else
#define rthal_virtualize_irq(dom, irq, isr, cookie, ackfn, mode) \
ipipe_virtualize_irq(dom, irq, isr, cookie, ackfn, mode)
#endif
struct xnintr;
typedef int (*xnisr_t)(struct xnintr *intr);
typedef int (*xniack_t)(unsigned irq);
typedef unsigned long xnflags_t;
typedef atomic_t atomic_counter_t;
typedef RTIME xnticks_t;
typedef struct xnstat_exectime {
xnticks_t start;
xnticks_t total;
} xnstat_exectime_t;
typedef struct xnstat_counter {
int counter;
} xnstat_counter_t;
#define xnstat_counter_inc(c) ((c)->counter++)
typedef struct xnintr {
#ifdef CONFIG_RTAI_RTDM_SHIRQ
struct xnintr *next;
#endif /* CONFIG_RTAI_RTDM_SHIRQ */
unsigned unhandled;
xnisr_t isr;
void *cookie;
xnflags_t flags;
unsigned irq;
xniack_t iack;
const char *name;
struct {
xnstat_counter_t hits;
xnstat_exectime_t account;
xnstat_exectime_t sum;
} stat[RTAI_NR_CPUS];
} xnintr_t;
#define xnsched_cpu(sched) rtai_cpuid()
int xnintr_shirq_attach(xnintr_t *intr, void *cookie);
int xnintr_shirq_detach(xnintr_t *intr);
int xnintr_init (xnintr_t *intr, const char *name, unsigned irq, xnisr_t isr, xniack_t iack, xnflags_t flags);
int xnintr_destroy (xnintr_t *intr);
int xnintr_attach (xnintr_t *intr, void *cookie);
int xnintr_detach (xnintr_t *intr);
int xnintr_enable (xnintr_t *intr);
int xnintr_disable (xnintr_t *intr);
/* Atomic operations are already serializing on x86 */
#define xnarch_before_atomic_dec() smp_mb__before_atomic_dec()
#define xnarch_after_atomic_dec() smp_mb__after_atomic_dec()
#define xnarch_before_atomic_inc() smp_mb__before_atomic_inc()
#define xnarch_after_atomic_inc() smp_mb__after_atomic_inc()
#define xnarch_memory_barrier() smp_mb()
#define xnarch_atomic_get(pcounter) atomic_read(pcounter)
#define xnarch_atomic_inc(pcounter) atomic_inc(pcounter)
#define xnarch_atomic_dec(pcounter) atomic_dec(pcounter)
#define testbits(flags, mask) ((flags) & (mask))
#define __testbits(flags, mask) ((flags) & (mask))
#define __setbits(flags, mask) do { (flags) |= (mask); } while(0)
#define __clrbits(flags, mask) do { (flags) &= ~(mask); } while(0)
#define xnarch_chain_irq rt_pend_linux_irq
#define xnarch_end_irq rt_enable_irq
#define xnarch_hook_irq(irq, handler, iack, intr) \
rt_request_irq_wack(irq, (void *)handler, intr, 0, (void *)iack);
#define xnarch_release_irq(irq) \
rt_release_irq(irq);
extern struct rtai_realtime_irq_s rtai_realtime_irq[];
//#define xnarch_get_irq_cookie(irq) (rtai_realtime_irq[irq].cookie)
#define xnarch_get_irq_cookie(irq) (rtai_domain.irqs[irq].cookie)
extern unsigned long IsolCpusMask;
#define xnarch_set_irq_affinity(irq, nkaffinity) \
rt_assign_irq_to_cpu(irq, IsolCpusMask)
// support for RTDM timers
struct rtdm_timer_struct {
struct rtdm_timer_struct *next, *prev;
int priority, cpuid;
RTIME firing_time, period;
void (*handler)(unsigned long);
unsigned long data;
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
rb_root_t rbr;
rb_node_t rbn;
#endif
};
RTAI_SYSCALL_MODE void rt_timer_remove(struct rtdm_timer_struct *timer);
RTAI_SYSCALL_MODE int rt_timer_insert(struct rtdm_timer_struct *timer, int priority, RTIME firing_time, RTIME period, void (*handler)(unsigned long), unsigned long data);
typedef struct rtdm_timer_struct xntimer_t;
#define XN_INFINITE (0)
/* Timer modes */
typedef enum xntmode {
XN_RELATIVE,
XN_ABSOLUTE,
XN_REALTIME
} xntmode_t;
#define xntbase_ns2ticks(rtdm_tbase, expiry) nano2count(expiry)
static inline void xntimer_init(xntimer_t *timer, void (*handler)(xntimer_t *))
{
memset(timer, 0, sizeof(struct rtdm_timer_struct));
timer->handler = (void *)handler;
timer->data = (unsigned long)timer;
timer->next = timer->prev = timer;
}
#define xntimer_set_name(timer, name)
static inline int xntimer_start(xntimer_t *timer, xnticks_t value, xnticks_t interval, int mode)
{
return rt_timer_insert(timer, 0, value, interval, timer->handler, (unsigned long)timer);
}
static inline void xntimer_destroy(xntimer_t *timer)
{
rt_timer_remove(timer);
}
static inline void xntimer_stop(xntimer_t *timer)
{
rt_timer_remove(timer);
}
// support for use in RTDM usage testing found in RTAI SHOWROOM CVS
static inline unsigned long long xnarch_ulldiv(unsigned long long ull, unsigned
long uld, unsigned long *r)
{
unsigned long rem = do_div(ull, uld);
if (r) {
*r = rem;
}
return ull;
}
// support for RTDM select
typedef struct xnholder {
struct xnholder *next;
struct xnholder *prev;
} xnholder_t;
typedef xnholder_t xnqueue_t;
#define DEFINE_XNQUEUE(q) xnqueue_t q = { { &(q), &(q) } }
#define inith(holder) \
do { *(holder) = (xnholder_t) { holder, holder }; } while (0)
#define initq(queue) \
do { inith(queue); } while (0)
#define appendq(queue, holder) \
do { \
(holder)->prev = (queue); \
((holder)->next = (queue)->next)->prev = holder; \
(queue)->next = holder; \
} while (0)
#define removeq(queue, holder) \
do { \
(holder)->prev->next = (holder)->next; \
(holder)->next->prev = (holder)->prev; \
} while (0)
static inline xnholder_t *getheadq(xnqueue_t *queue)
{
xnholder_t *holder = queue->next;
return holder == queue ? NULL : holder;
}
static inline xnholder_t *getq(xnqueue_t *queue)
{
xnholder_t *holder;
if ((holder = getheadq(queue))) {
removeq(queue, holder);
}
return holder;
}
static inline xnholder_t *nextq(xnqueue_t *queue, xnholder_t *holder)
{
xnholder_t *nextholder = holder->next;
return nextholder == queue ? NULL : nextholder;
}
static inline int emptyq_p(xnqueue_t *queue)
{
return queue->next == queue;
}
#include "rtai_taskq.h"
#define xnpod_schedule rt_schedule_readied
#define xnthread_t RT_TASK
#define xnpod_current_thread _rt_whoami
#define xnthread_test_info rt_task_test_taskq_retval
#define xnsynch_t TASKQ
#define xnsynch_init(s, f, p) rt_taskq_init(s, f)
#define xnsynch_destroy rt_taskq_delete
#define xnsynch_wakeup_one_sleeper rt_taskq_ready_one
#define xnsynch_flush rt_taskq_ready_all
static inline void xnsynch_sleep_on(void *synch, xnticks_t timeout, xntmode_t timeout_mode)
{
if (timeout == XN_INFINITE) {
rt_taskq_wait(synch);
} else {
rt_taskq_wait_until(synch, timeout_mode == XN_RELATIVE ? rt_get_time() + timeout : timeout);
}
}
#define XNSYNCH_NOPIP 0
#define XNSYNCH_PRIO TASKQ_PRIO
#define XNSYNCH_FIFO TASKQ_FIFO
#define XNSYNCH_RESCHED 1
#define rthal_apc_alloc(name, handler, cookie) \
rt_request_srq(nam2num(name), (void *)(handler), NULL);
#define rthal_apc_free(apc) \
rt_free_srq((apc))
#define __rthal_apc_schedule(apc) \
hal_pend_uncond(apc, rtai_cpuid())
#define rthal_apc_schedule(apc) \
rt_pend_linux_srq((apc))
#ifdef CONFIG_RTAI_RTDM_SELECT
#define SELECT_SIGNAL(select_block, state) \
do { \
spl_t flags; \
xnlock_get_irqsave(&nklock, flags); \
if (xnselect_signal(select_block, state) && state) { \
xnpod_schedule(); \
} \
xnlock_put_irqrestore(&nklock, flags); \
} while (0)
#else
#define SELECT_SIGNAL(select_block, state) do { } while (0)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define __WORK_INITIALIZER(n,f,d) { \
.list = { &(n).list, &(n).list }, \
.sync = 0, \
.routine = (f), \
.data = (d), \
}
#define DECLARE_WORK(n,f,d) struct tq_struct n = __WORK_INITIALIZER(n, f, d)
#define DECLARE_WORK_NODATA(n, f) DECLARE_WORK(n, f, NULL)
#define DECLARE_WORK_FUNC(f) void f(void *cookie)
#define DECLARE_DELAYED_WORK_NODATA(n, f) DECLARE_WORK(n, f, NULL)
#define schedule_delayed_work(work, delay) do { \
if (delay) { \
set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout(delay); \
} \
schedule_task(work); \
} while (0)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#define DECLARE_WORK_NODATA(f, n) DECLARE_WORK(f, n, NULL)
#define DECLARE_WORK_FUNC(f) void f(void *cookie)
#define DECLARE_DELAYED_WORK_NODATA(n, f) DECLARE_DELAYED_WORK(n, f, NULL)
#else /* >= 2.6.20 */
#define DECLARE_WORK_NODATA(f, n) DECLARE_WORK(f, n)
#define DECLARE_WORK_FUNC(f) void f(struct work_struct *work)
#define DECLARE_DELAYED_WORK_NODATA(n, f) DECLARE_DELAYED_WORK(n, f)
#endif /* >= 2.6.20 */
#endif
#endif /* !_RTAI_XNSTUFF_H */

37
base/GNUmakefile.am Normal file
View file

@ -0,0 +1,37 @@
OPTDIRS = include
# `malloc', in $(OPTDIRS), must be after `sched' when compiling
# with kernel 2.4 and builtin RTAI malloc support
if CONFIG_RTAI_MALLOC
OPTDIRS += malloc
endif
OPTDIRS += sched ipc arch posix
if CONFIG_RTAI_TRACE
OPTDIRS += trace
endif
if CONFIG_RTAI_MATH
OPTDIRS += math
endif
if CONFIG_RTAI_TASKLETS
OPTDIRS += tasklets
endif
if CONFIG_RTAI_USI
OPTDIRS += usi
endif
if CONFIG_RTAI_WD
OPTDIRS += wd
endif
if CONFIG_RTAI_LEDS
OPTDIRS += leds
endif
SUBDIRS = $(OPTDIRS) scripts
EXTRA_DIST = config

36
base/arch/GNUmakefile.am Normal file
View file

@ -0,0 +1,36 @@
if CONFIG_X86
ARCHDIR = x86
endif
#if CONFIG_I386
#ARCHDIR = i386
#endif
#if CONFIG_X86_64
#ARCHDIR = x86_64
#endif
if CONFIG_ARM
ARCHDIR = arm
endif
if CONFIG_PPC
ARCHDIR = ppc
endif
if CONFIG_M68KNOMMU
ARCHDIR = m68k
endif
if CONFIG_M68K
ARCHDIR = m68k
endif
SUBDIRS = $(ARCHDIR)
modext = @RTAI_MODULE_EXT@
rtai_hal$(modext):
@(cd $(ARCHDIR)/hal && make rtai_hal$(modext))
#EXTRA_DIST = x86/patches

Some files were not shown because too many files have changed in this diff Show more