Compare commits

..

1 commit

Author SHA1 Message Date
Jeff Epler
04c0b06102 Remove files that do not have a distributable license
These files do not carry a licences that makes them distributable.
However, all of them appear to be either unused or not required by
linuxcnc, based on my analysis at
    http://mid.gmane.org/20131101024943.GA31516%40unpythonic.net
2014-08-20 07:04:33 -05:00
1082 changed files with 273406 additions and 32745 deletions

1
.gitignore vendored
View file

@ -31,7 +31,6 @@ addons/drivers/16550A/FORCE
# Generated Makefiles
GNUmakefile.in
GNUmakefile
Makefile.in
Makefile
# Config Temp Files

4300
ChangeLog Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,28 +1,53 @@
ACLOCAL_AMFLAGS=-I base/config/autoconf
OPTDIRS =
OPTDIRS += addons
if CONFIG_RTAI_TESTSUITE
OPTDIRS += testsuite
endif
SUBDIRS = base $(OPTDIRS)
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 \
addons
testsuite \
addons \
rtai-lab \
rtai-py
EXTRA_DIST = \
makefile \
README.INSTALL \
README.ISOLCPUS \
README.LINUX_SERVER \
README.LXRT_EXTS_IN_USE \
README.SMI
README.SMI \
@RTAI_MAYBE_SIMDIR@
DISTCLEANFILES = .rtai_config .rtai_config.old .cfok .cfchanged Module.symvers configure
DISTCLEANFILES = .rtai_config .rtai_config.old .cfok .cfchanged Module.symvers
moduledir = @RTAI_MODULE_DIR@
MAKEFLAGS := $(MAKEFLAGS) --no-print-directory
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 ; \
@ -33,41 +58,9 @@ clean-if-reconfigured:
$(MAKE) clean ; \
fi
CONFIG_METHODS := config nconfig menuconfig xconfig gconfig oldconfig silentoldconfig defconfig \
savedefconfig allnoconfig allyesconfig allmodconfig alldefconfig \
randconfig listnewconfig olddefconfig
.PHONY: $(CONFIG_METHODS)
$(CONFIG_METHODS):
@$(MAKE) -C base/config/kconfig \
-f Makefile.kconfig $@ \
srctree=$(PWD) ARCH=`uname -m`
@$(MAKE) --no-print-directory config-status
config-status: .rtai_config
@test -r config.status && recf=yes || recf=no ; \
eval `grep ^CONFIG_RTAI_INSTALLDIR $<`; \
CC="$(CC)" \
CXX="$(CXX)" \
LD="$(LD)" \
AR="$(AR)" \
RANLIB=ranlib \
STRIP=strip \
NM=nm \
$(srctree)./configure \
--build=$(build_alias) \
--host=$(host_alias) \
--with-kconfig-file=./$< \
--with-linux-dir=$(RTAI_LINUX_DIR) \
--prefix=$$CONFIG_RTAI_INSTALLDIR \
$$confopts ; \
if test $$? = 0; then \
touch .cfok ; \
if test x$$recf = xyes ; then \
touch .cfchanged ; \
fi ; \
else \
rm -f .cfok ; false; \
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:
@ -105,21 +98,21 @@ dist-hook:
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" ; \
$(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" ; \
$(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 \
@ -130,9 +123,9 @@ dev devices:
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; \
$$sudo mknod -m 666 $$f c 150 $$n; \
fi; \
done ; \
fi
.PHONY: clean-if-reconfigured dev devices
.PHONY: reconfig xconfig gconfig mconfig menuconfig config oldconfig clean-if-reconfigured dev devices

View file

@ -1 +0,0 @@
ACLOCAL_AMFLAGS = -I m4

View file

@ -168,7 +168,17 @@ 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 Installing the software
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:
@ -203,7 +213,7 @@ 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.3 Compiling parts of the tree
1.4 Compiling parts of the tree
-------------------------------
RTAI developers may want to recompile parts of the tree from times to
@ -216,7 +226,7 @@ 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.4 Changing the configuration
1.5 Changing the configuration
------------------------------
Each time you want to change your configuration, just run "make
@ -231,7 +241,7 @@ 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.5 Modifying the autotool template files
1.6 Modifying the autotool template files
-----------------------------------------
If you have to change some template files used by any of the autotools
@ -243,7 +253,7 @@ o automake 1.9.2
o aclocal 1.9.2
o libtool 1.5.8
1.6 Using the integrated calibration tool
1.7 Using the integrated calibration tool
-----------------------------------------
RTAI 3.x comes with a brand new calibration tool which should help you

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.

View file

@ -1,5 +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

@ -3,7 +3,7 @@ includedir = $(prefix)/include/rtdm
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
librtdm_a_SOURCES = \
core.c \
@ -12,8 +12,7 @@ librtdm_a_SOURCES = \
module.c \
proc.c \
rtai_taskq.c \
select.c \
vfile.c
select.c
include_HEADERS = \
rtdm.h \
@ -21,8 +20,7 @@ include_HEADERS = \
rtserial.h \
xn.h \
rtai_taskq.h \
select.h \
vfile.h
select.h
if CONFIG_KBUILD
rtai_rtdm$(modext): @RTAI_KBUILD_ENV@
@ -41,9 +39,9 @@ else
noinst_LIBRARIES = librtdm.a
librtdm_a_AR = ar cru
librtdm_a_AR = $(CROSS_COMPILE)ar cru
AM_CPPFLAGS = \
INCLUDES = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I$(top_srcdir)/addons \
@ -52,7 +50,7 @@ AM_CPPFLAGS = \
-I..
rtai_rtdm.o: librtdm.a
$(LD) --whole-archive $< -r -o $@
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
endif
all-local: rtai_rtdm$(modext)

View file

@ -5,10 +5,15 @@ librtdm_la_LDFLAGS = -module -version-info 0:0:0
librtdm_la_SOURCES = \
services.c
AM_CPPFLAGS = \
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

@ -16,4 +16,8 @@
* 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 */

View file

@ -2,7 +2,7 @@
* Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de>.
* Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net>.
*
* adapted to RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
* 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
@ -19,427 +19,299 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "rtdm/internal.h"
#include <rtdm/vfile.h>
struct xnvfile_directory rtdm_vfroot; /* /proc/rtai/rtdm */
/* Derived from Erwin Rol's rtai_proc_fs.h.
Assumes that output fits into the provided buffer. */
struct vfile_device_data {
int h;
int hmax;
struct list_head *devmap;
struct list_head *curr;
};
#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
static int get_nrt_lock(struct xnvfile *vfile)
#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)
{
return down_interruptible(&nrt_dev_lock) ? -ERESTARTSYS : 0;
}
static void put_nrt_lock(struct xnvfile *vfile)
{
up(&nrt_dev_lock);
}
static struct xnvfile_lock_ops lockops = {
.get = get_nrt_lock,
.put = put_nrt_lock,
};
static struct list_head *next_devlist(struct vfile_device_data *priv)
{
struct list_head *head;
while (priv->h < priv->hmax) {
head = priv->devmap + priv->h;
if (!list_empty(head))
return head;
priv->h++;
}
return NULL;
}
static void *next_dev(struct xnvfile_regular_iterator *it)
{
struct vfile_device_data *priv = xnvfile_iterator_priv(it);
struct list_head *next;
next = priv->curr->next;
seek:
if (next == priv->devmap + priv->h) {
/* Done with the current hash slot, let's progress. */
if (priv->h >= priv->hmax) {
next = NULL; /* all done. */
goto out;
}
priv->h++;
next = next_devlist(priv);
if (next) {
next = next->next; /* skip head. */
goto seek;
}
}
out:
priv->curr = next;
return next;
}
static void *named_begin(struct xnvfile_regular_iterator *it)
{
struct vfile_device_data *priv = xnvfile_iterator_priv(it);
struct list_head *devlist;
loff_t pos = 0;
priv->devmap = rtdm_named_devices;
priv->hmax = devname_hashtab_size;
priv->h = 0;
devlist = next_devlist(priv);
if (devlist == NULL)
return NULL; /* All devlists empty. */
priv->curr = devlist->next; /* Skip head. */
/*
* priv->curr now points to the first device; advance to the requested
* position from there.
*/
while (priv->curr && pos++ < it->pos)
priv->curr = next_dev(it);
if (pos == 1)
/* Output the header once, only if some device follows. */
xnvfile_puts(it, "Hash\tName\t\t\t\tDriver\t\t/proc\n");
return priv->curr;
}
static int named_show(struct xnvfile_regular_iterator *it, void *data)
{
struct vfile_device_data *priv = xnvfile_iterator_priv(it);
struct list_head *curr = data;
struct rtdm_device *device;
device = list_entry(curr, struct rtdm_device, reserved.entry);
xnvfile_printf(it, "%02X\t%-31s\t%-15s\t%s\n",
priv->h, device->device_name,
device->driver_name,
device->proc_name);
return 0;
}
static struct xnvfile_regular_ops named_vfile_ops = {
.begin = named_begin,
.next = next_dev,
.show = named_show,
};
static struct xnvfile_regular named_vfile = {
.privsz = sizeof(struct vfile_device_data),
.ops = &named_vfile_ops,
.entry = { .lockops = &lockops }
};
static void *proto_begin(struct xnvfile_regular_iterator *it)
{
struct vfile_device_data *priv = xnvfile_iterator_priv(it);
struct list_head *devlist;
loff_t pos = 0;
priv->devmap = rtdm_protocol_devices;
priv->hmax = protocol_hashtab_size;
priv->h = 0;
devlist = next_devlist(priv);
if (devlist == NULL)
return NULL; /* All devlists empty. */
priv->curr = devlist->next; /* Skip head. */
/*
* priv->curr now points to the first device; advance to the requested
* position from there.
*/
while (priv->curr && pos++ < it->pos)
priv->curr = next_dev(it);
if (pos == 1)
/* Output the header once, only if some device follows. */
xnvfile_puts(it, "Hash\tName\t\t\t\tDriver\t\t/proc\n");
return priv->curr;
}
static int proto_show(struct xnvfile_regular_iterator *it, void *data)
{
struct vfile_device_data *priv = xnvfile_iterator_priv(it);
struct list_head *curr = data;
struct rtdm_device *device;
char pnum[32];
device = list_entry(curr, struct rtdm_device, reserved.entry);
snprintf(pnum, sizeof(pnum), "%u:%u",
device->protocol_family, device->socket_type);
xnvfile_printf(it, "%02X\t%-31s\t%-15s\t%s\n",
priv->h,
pnum, device->driver_name,
device->proc_name);
return 0;
}
static struct xnvfile_regular_ops proto_vfile_ops = {
.begin = proto_begin,
.next = next_dev,
.show = proto_show,
};
static struct xnvfile_regular proto_vfile = {
.privsz = sizeof(struct vfile_device_data),
.ops = &proto_vfile_ops,
.entry = { .lockops = &lockops }
};
static void *openfd_begin(struct xnvfile_regular_iterator *it)
{
if (it->pos == 0)
return VFILE_SEQ_START;
return it->pos <= RTDM_FD_MAX ? it : NULL;
}
static void *openfd_next(struct xnvfile_regular_iterator *it)
{
if (it->pos > RTDM_FD_MAX)
return NULL;
return it;
}
static int openfd_show(struct xnvfile_regular_iterator *it, void *data)
{
struct rtdm_dev_context *context;
struct rtdm_device *device;
struct rtdm_process owner;
int close_lock_count, fd;
spl_t s;
if (data == NULL) {
xnvfile_puts(it, "Index\tLocked\tDevice\t\t\t\tOwner [PID]\n");
return 0;
}
fd = (int)it->pos - 1;
xnlock_get_irqsave(&rt_fildes_lock, s);
context = fildes_table[fd].context;
if (context == NULL) {
xnlock_put_irqrestore(&rt_fildes_lock, s);
return VFILE_SEQ_SKIP;
}
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);
xnvfile_printf(it, "%d\t%d\t%-31s %s [%d]\n", fd,
close_lock_count,
(device->device_flags & RTDM_NAMED_DEVICE) ?
device->device_name : device->proc_name,
owner.name, owner.pid);
return 0;
}
static ssize_t openfd_store(struct xnvfile_input *input)
{
ssize_t ret, cret;
long val;
ret = xnvfile_get_integer(input, &val);
if (ret < 0)
return ret;
cret = __rt_dev_close(current, (int)val);
if (cret < 0)
return cret;
return ret;
}
static struct xnvfile_regular_ops openfd_vfile_ops = {
.begin = openfd_begin,
.next = openfd_next,
.show = openfd_show,
.store = openfd_store,
};
static struct xnvfile_regular openfd_vfile = {
.ops = &openfd_vfile_ops,
.entry = { .lockops = &lockops }
};
static int allfd_vfile_show(struct xnvfile_regular_iterator *it, void *data)
{
xnvfile_printf(it, "total=%d:open=%d:free=%d\n", RTDM_FD_MAX,
open_fildes, RTDM_FD_MAX - open_fildes);
return 0;
}
static struct xnvfile_regular_ops allfd_vfile_ops = {
.show = allfd_vfile_show,
};
static struct xnvfile_regular allfd_vfile = {
.ops = &allfd_vfile_ops,
};
static int devinfo_vfile_show(struct xnvfile_regular_iterator *it, void *data)
{
struct rtdm_device *device;
int i;
struct list_head *entry;
struct rtdm_device *device;
RTDM_PROC_PRINT_VARS(80);
if (down_interruptible(&nrt_dev_lock))
return -ERESTARTSYS;
/*
* As the device may have disappeared while the handler was called,
* first match the pointer against registered devices.
*/
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(device, &rtdm_named_devices[i],
reserved.entry)
if (device == xnvfile_priv(it->vfile))
goto found;
list_for_each(entry, &rtdm_named_devices[i]) {
device = list_entry(entry, struct rtdm_device,
reserved.entry);
for (i = 0; i < protocol_hashtab_size; i++)
list_for_each_entry(device, &rtdm_protocol_devices[i],
reserved.entry)
if (device == xnvfile_priv(it->vfile))
goto found;
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);
return -ENODEV;
found:
xnvfile_printf(it, "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));
xnvfile_printf(it, "peripheral:\t%s\nprovider:\t%s\n",
device->peripheral_name, device->provider_name);
xnvfile_printf(it, "class:\t\t%d\nsub-class:\t%d\n",
device->device_class, device->device_sub_class);
xnvfile_printf(it, "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 " : "");
xnvfile_printf(it, "lock count:\t%d\n",
atomic_read(&device->reserved.refcount));
up(&nrt_dev_lock);
return 0;
RTDM_PROC_PRINT_DONE;
}
static struct xnvfile_regular_ops devinfo_vfile_ops = {
.show = devinfo_vfile_show,
};
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)
{
int ret;
struct proc_dir_entry *dev_dir;
struct proc_dir_entry *proc_entry;
ret = xnvfile_init_dir(device->proc_name,
&device->vfroot, &rtdm_vfroot);
if (ret)
dev_dir = create_proc_entry(device->proc_name, S_IFDIR, rtdm_proc_root);
if (!dev_dir)
goto err_out;
memset(&device->info_vfile, 0, sizeof(device->info_vfile));
device->info_vfile.ops = &devinfo_vfile_ops;
ret = xnvfile_init_regular("information", &device->info_vfile,
&device->vfroot);
if (ret) {
xnvfile_destroy_dir(&device->vfroot);
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;
xnvfile_priv(&device->info_vfile) = device;
device->proc_entry = dev_dir;
return 0;
err_out:
xnlogerr("RTDM: error while creating device vfile\n");
return ret;
xnlogerr("RTDM: error while creating device proc entry\n");
return -EAGAIN;
}
void rtdm_proc_unregister_device(struct rtdm_device *device)
{
xnvfile_destroy_regular(&device->info_vfile);
xnvfile_destroy_dir(&device->vfroot);
remove_proc_entry("information", device->proc_entry);
remove_proc_entry(device->proc_name, rtdm_proc_root);
}
int __init rtdm_proc_init(void)
{
int ret;
struct proc_dir_entry *proc_entry;
/* Initialise vfiles */
// ret = xnvfile_init_root(); /proc/rtai is initted elsewhere
ret = xnvfile_init_dir("rtai/rtdm", &rtdm_vfroot, &nkvfroot);
if (ret)
goto error;
/* Initialise /proc entries */
rtdm_proc_root = create_proc_entry("rtai/rtdm", S_IFDIR, NULL);
if (!rtdm_proc_root)
return -EAGAIN;
ret = xnvfile_init_regular("named_devices", &named_vfile, &rtdm_vfroot);
if (ret)
goto error;
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;
ret = xnvfile_init_regular("protocol_devices", &proto_vfile, &rtdm_vfroot);
if (ret)
goto error;
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;
ret = xnvfile_init_regular("open_fildes", &openfd_vfile, &rtdm_vfroot);
if (ret)
goto error;
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;
ret = xnvfile_init_regular("fildes", &allfd_vfile, &rtdm_vfroot);
if (ret)
goto error;
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;
error:
rtdm_proc_cleanup();
return ret;
}
void rtdm_proc_cleanup(void)
{
xnvfile_destroy_regular(&allfd_vfile);
xnvfile_destroy_regular(&openfd_vfile);
xnvfile_destroy_regular(&proto_vfile);
xnvfile_destroy_regular(&named_vfile);
xnvfile_destroy_dir(&rtdm_vfroot);
// xnvfile_destroy_root(); /proc/rtai is destroyed elsewhere
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);
}

View file

@ -40,7 +40,6 @@
#include "xn.h"
#include "select.h"
#include <rtdm/vfile.h>
#include <rtdm/rtdm.h>
@ -510,12 +509,6 @@ struct rtdm_device {
/** Name of /proc entry for the device, must not be NULL */
const char *proc_name;
#ifdef CONFIG_PROC_FS
/** Set to device's vfile data after registration, do not modify */
struct xnvfile_directory vfroot;
struct xnvfile_regular info_vfile;
#endif
/** Set to device's /proc root entry after registration, do not modify */
struct proc_dir_entry *proc_entry;

View file

@ -1,970 +0,0 @@
/**
* @file
* This file is part of the Xenomai project.
*
* @note Copyright (C) 2010 Philippe Gerum <rpm@xenomai.org>
*
* adapted to RTAI by 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.
*/
/*!
* @ingroup nucleus
* @defgroup vfile Virtual file services
*
* Virtual files provide a mean to export RTAI object states to
* user-space, based on common kernel interfaces. This encapsulation
* is aimed at:
*
* - supporting consistent collection of very large record-based
* output, without encurring latency peaks for undergoing real-time
* activities.
*
* - in the future, hiding discrepancies between linux kernel
* releases, regarding the proper way to export kernel object states
* to userland, either via the /proc interface or by any other mean.
*
* This virtual file implementation offers record-based read support
* based on seq_files, single-buffer write support, directory and link
* handling, all visible from the /proc namespace.
*
* The vfile support exposes four filesystem object types:
*
* - snapshot-driven file (struct xnvfile_snapshot). This is commonly
* used to export real-time object states via the /proc filesystem. To
* minimize the latency involved in protecting the vfile routines from
* changes applied by real-time code on such objects, a snapshot of
* the data to output is first taken under proper locking, before the
* collected data is formatted and sent out in a lockless manner.
*
* Because a large number of records may have to be output, the data
* collection phase is not strictly atomic as a whole, but only
* protected at record level. The vfile implementation can be notified
* of updates to the underlying data set, and restart the collection
* from scratch until the snapshot is fully consistent.
*
* - regular sequential file (struct xnvfile_regular). This is
* basically an encapsulated sequential file object as available from
* the host kernel (i.e. seq_file), with a few additional features to
* make it more handy in an RTAI environment, like implicit locking
* support and shortened declaration for simplest, single-record
* output.
*
* - virtual link (struct xnvfile_link). This is a symbolic link
* feature integrated with the vfile semantics. The link target is
* computed dynamically at creation time from a user-given helper
* routine.
*
* - virtual directory (struct xnvfile_directory). A directory object,
* which can be used to create a hierarchy for ordering a set of vfile
* objects.
*
*@{*/
#include <stdarg.h>
#include <linux/ctype.h>
#include <rtdm/vfile.h>
/**
* @var struct xnvfile_directory nkvfroot
* @brief RTAI vfile root directory
*
* This vdir maps the /proc/rtai directory. It can be used to
* create a hierarchy of RTAI-related vfiles under this root.
*/
struct xnvfile_directory nkvfroot;
EXPORT_SYMBOL_GPL(nkvfroot);
static struct xnvfile_directory sysroot;
static void *vfile_snapshot_start(struct seq_file *seq, loff_t *offp)
{
struct xnvfile_snapshot_iterator *it = seq->private;
loff_t pos = *offp;
if (pos > it->nrdata)
return NULL;
if (pos == 0)
return SEQ_START_TOKEN;
return it->databuf + (pos - 1) * it->vfile->datasz;
}
static void *vfile_snapshot_next(struct seq_file *seq, void *v, loff_t *offp)
{
struct xnvfile_snapshot_iterator *it = seq->private;
loff_t pos = *offp;
if (pos >= it->nrdata)
return NULL;
++*offp;
return it->databuf + pos * it->vfile->datasz;
}
static void vfile_snapshot_stop(struct seq_file *seq, void *v)
{
}
static int vfile_snapshot_show(struct seq_file *seq, void *v)
{
struct xnvfile_snapshot_iterator *it = seq->private;
void *data = v == SEQ_START_TOKEN ? NULL : v;
int ret;
ret = it->vfile->ops->show(it, data);
return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret;
}
static struct seq_operations vfile_snapshot_ops = {
.start = vfile_snapshot_start,
.next = vfile_snapshot_next,
.stop = vfile_snapshot_stop,
.show = vfile_snapshot_show
};
static void vfile_snapshot_free(struct xnvfile_snapshot_iterator *it, void *buf)
{
kfree(buf);
}
static int vfile_snapshot_open(struct inode *inode, struct file *file)
{
struct xnvfile_snapshot *vfile = PDE_DATA(inode);
struct xnvfile_snapshot_ops *ops = vfile->ops;
struct xnvfile_snapshot_iterator *it;
int revtag, ret, nrdata;
struct seq_file *seq;
caddr_t data;
if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL)
return -EACCES;
/*
* Make sure to create the seq_file backend only when reading
* from the v-file is possible.
*/
if ((file->f_mode & FMODE_READ) == 0) {
file->private_data = NULL;
return 0;
}
if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
return -EBUSY;
it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL);
if (it == NULL)
return -ENOMEM;
it->vfile = vfile;
xnvfile_file(vfile) = file;
ret = vfile->entry.lockops->get(&vfile->entry);
if (ret)
goto fail;
redo:
/*
* The ->rewind() method is optional; there may be cases where
* we don't have to take an atomic snapshot of the v-file
* contents before proceeding. In case ->rewind() detects a
* stale backend object, it can force us to bail out.
*
* If present, ->rewind() may return a strictly positive
* value, indicating how many records at most may be returned
* by ->next(). We use this hint to allocate the snapshot
* buffer, in case ->begin() is not provided. The size of this
* buffer would then be vfile->datasz * hint value.
*
* If ->begin() is given, we always expect the latter do the
* allocation for us regardless of the hint value. Otherwise,
* a NULL return from ->rewind() tells us that the vfile won't
* output any snapshot data via ->show().
*/
nrdata = 0;
if (ops->rewind) {
nrdata = ops->rewind(it);
if (nrdata < 0) {
ret = nrdata;
vfile->entry.lockops->put(&vfile->entry);
goto fail;
}
}
revtag = vfile->tag->rev;
vfile->entry.lockops->put(&vfile->entry);
/* Release the data buffer, in case we had to restart. */
if (it->databuf) {
it->endfn(it, it->databuf);
it->databuf = NULL;
}
/*
* Having no record to output is fine, in which case ->begin()
* shall return VFILE_SEQ_EMPTY if present. ->begin() may be
* absent, meaning that no allocation is even required to
* collect the records to output. NULL is kept for allocation
* errors in all other cases.
*/
if (ops->begin) {
RTAI_BUGON(NUCLEUS, ops->end == NULL);
data = ops->begin(it);
if (data == NULL) {
kfree(it);
return -ENOMEM;
}
if (data != VFILE_SEQ_EMPTY) {
it->databuf = data;
it->endfn = ops->end;
}
} else if (nrdata > 0 && vfile->datasz > 0) {
/* We have a hint for auto-allocation. */
data = kmalloc(vfile->datasz * nrdata, GFP_KERNEL);
if (data == NULL) {
kfree(it);
return -ENOMEM;
}
it->databuf = data;
it->endfn = vfile_snapshot_free;
}
ret = seq_open(file, &vfile_snapshot_ops);
if (ret)
goto fail;
it->nrdata = 0;
data = it->databuf;
if (data == NULL)
goto finish;
/*
* Take a snapshot of the vfile contents, redo if the revision
* tag of the scanned data set changed concurrently.
*/
for (;;) {
ret = vfile->entry.lockops->get(&vfile->entry);
if (ret)
break;
if (vfile->tag->rev != revtag)
goto redo;
ret = ops->next(it, data);
vfile->entry.lockops->put(&vfile->entry);
if (ret <= 0)
break;
if (ret != VFILE_SEQ_SKIP) {
data += vfile->datasz;
it->nrdata++;
}
}
if (ret < 0) {
seq_release(inode, file);
fail:
if (it->databuf)
it->endfn(it, it->databuf);
kfree(it);
return ret;
}
finish:
seq = file->private_data;
it->seq = seq;
seq->private = it;
xnvfile_nref(vfile)++;
return 0;
}
static int vfile_snapshot_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct xnvfile_snapshot_iterator *it;
if (seq) {
it = seq->private;
if (it) {
--xnvfile_nref(it->vfile);
RTAI_BUGON(NUCLEUS, it->vfile->entry.refcnt < 0);
if (it->databuf)
it->endfn(it, it->databuf);
kfree(it);
}
return seq_release(inode, file);
}
return 0;
}
ssize_t vfile_snapshot_write(struct file *file, const char __user *buf,
size_t size, loff_t *ppos)
{
struct xnvfile_snapshot *vfile = PDE_DATA(wrap_f_inode(file));
struct xnvfile_input input;
ssize_t ret;
if (vfile->entry.lockops) {
ret = vfile->entry.lockops->get(&vfile->entry);
if (ret)
return ret;
}
input.u_buf = buf;
input.size = size;
input.vfile = &vfile->entry;
ret = vfile->ops->store(&input);
if (vfile->entry.lockops)
vfile->entry.lockops->put(&vfile->entry);
return ret;
}
static struct file_operations vfile_snapshot_fops = {
.owner = THIS_MODULE,
.open = vfile_snapshot_open,
.read = seq_read,
.write = vfile_snapshot_write,
.llseek = seq_lseek,
.release = vfile_snapshot_release,
};
/**
* @fn int xnvfile_init_snapshot(const char *name, struct xnvfile_snapshot *vfile, struct xnvfile_directory *parent)
* @brief Initialize a snapshot-driven vfile.
*
* @param name The name which should appear in the pseudo-filesystem,
* identifying the vfile entry.
*
* @param vfile A pointer to a vfile descriptor to initialize
* from. The following fields in this structure should be filled in
* prior to call this routine:
*
* - .privsz is the size (in bytes) of the private data area to be
* reserved in the @ref snapshot_iterator "vfile iterator". A NULL
* value indicates that no private area should be reserved.
*
* - .datasz is the size (in bytes) of a single record to be collected
* by the @ref snapshot_next "next() handler" from the @ref
* snapshot_ops "operation descriptor".
*
* - .tag is a pointer to a mandatory vfile revision tag structure
* (struct xnvfile_rev_tag). This tag will be monitored for changes by
* the vfile core while collecting data to output, so that any update
* detected will cause the current snapshot data to be dropped, and
* the collection to restart from the beginning. To this end, any
* change to the data which may be part of the collected records,
* should also invoke xnvfile_touch() on the associated tag.
*
* - entry.lockops is a pointer to a @ref vfile_lockops "locking
* descriptor", defining the lock and unlock operations for the
* vfile. This pointer may be left to NULL, in which case the
* operations on the nucleus lock (i.e. nklock) will be used
* internally around calls to data collection handlers (see @ref
* snapshot_ops "operation descriptor").
*
* - .ops is a pointer to an @ref snapshot_ops "operation descriptor".
*
* @param parent A pointer to a virtual directory descriptor; the
* vfile entry will be created into this directory. If NULL, the /proc
* root directory will be used. /proc/rtai is mapped on the
* globally available @a nkvfroot vdir.
*
* @return 0 is returned on success. Otherwise:
*
* - -ENOMEM is returned if the virtual file entry cannot be created
* in the /proc hierarchy.
*/
int xnvfile_init_snapshot(const char *name,
struct xnvfile_snapshot *vfile,
struct xnvfile_directory *parent)
{
struct proc_dir_entry *ppde, *pde;
int mode;
RTAI_BUGON(NUCLEUS, vfile->tag == NULL);
if (vfile->entry.lockops == NULL)
/* Defaults to nucleus lock */
vfile->entry.lockops = &xnvfile_nucleus_lock.ops;
if (parent == NULL)
parent = &sysroot;
mode = vfile->ops->store ? 0644 : 0444;
ppde = parent->entry.pde;
pde = proc_create_data(name, mode, ppde, &vfile_snapshot_fops, vfile);
if (pde == NULL)
return -ENOMEM;
wrap_proc_dir_entry_owner(pde);
vfile->entry.pde = pde;
return 0;
}
EXPORT_SYMBOL_GPL(xnvfile_init_snapshot);
static void *vfile_regular_start(struct seq_file *seq, loff_t *offp)
{
struct xnvfile_regular_iterator *it = seq->private;
struct xnvfile_regular *vfile = it->vfile;
int ret;
it->pos = *offp;
if (vfile->entry.lockops) {
ret = vfile->entry.lockops->get(&vfile->entry);
if (ret)
return ERR_PTR(ret);
}
/*
* If we have no begin() op, then we allow a single call only
* to ->show(), by returning the start token once. Otherwise,
* we are done.
*/
if (vfile->ops->begin == NULL)
return it->pos > 0 ? NULL : SEQ_START_TOKEN;
return vfile->ops->begin(it);
}
static void *vfile_regular_next(struct seq_file *seq, void *v, loff_t *offp)
{
struct xnvfile_regular_iterator *it = seq->private;
struct xnvfile_regular *vfile = it->vfile;
void *data;
if (vfile->ops->next == NULL)
return NULL;
it->pos = *offp + 1;
data = vfile->ops->next(it);
if (data == NULL)
return NULL;
*offp = it->pos;
return data;
}
static void vfile_regular_stop(struct seq_file *seq, void *v)
{
struct xnvfile_regular_iterator *it = seq->private;
struct xnvfile_regular *vfile = it->vfile;
if (vfile->entry.lockops)
vfile->entry.lockops->put(&vfile->entry);
if (vfile->ops->end)
vfile->ops->end(it);
}
static int vfile_regular_show(struct seq_file *seq, void *v)
{
struct xnvfile_regular_iterator *it = seq->private;
struct xnvfile_regular *vfile = it->vfile;
void *data = v == SEQ_START_TOKEN ? NULL : v;
int ret;
ret = vfile->ops->show(it, data);
return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret;
}
static struct seq_operations vfile_regular_ops = {
.start = vfile_regular_start,
.next = vfile_regular_next,
.stop = vfile_regular_stop,
.show = vfile_regular_show
};
static int vfile_regular_open(struct inode *inode, struct file *file)
{
struct xnvfile_regular *vfile = PDE_DATA(inode);
struct xnvfile_regular_ops *ops = vfile->ops;
struct xnvfile_regular_iterator *it;
struct seq_file *seq;
int ret;
if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
return -EBUSY;
if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL)
return -EACCES;
if ((file->f_mode & FMODE_READ) == 0) {
file->private_data = NULL;
return 0;
}
it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL);
if (it == NULL)
return -ENOMEM;
it->vfile = vfile;
it->pos = -1;
xnvfile_file(vfile) = file;
if (ops->rewind) {
ret = ops->rewind(it);
if (ret) {
fail:
kfree(it);
return ret;
}
}
ret = seq_open(file, &vfile_regular_ops);
if (ret)
goto fail;
seq = file->private_data;
it->seq = seq;
seq->private = it;
xnvfile_nref(vfile)++;
return 0;
}
static int vfile_regular_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct xnvfile_regular_iterator *it;
if (seq) {
it = seq->private;
if (it) {
--xnvfile_nref(it->vfile);
RTAI_BUGON(NUCLEUS, xnvfile_nref(it->vfile) < 0);
kfree(it);
}
return seq_release(inode, file);
}
return 0;
}
ssize_t vfile_regular_write(struct file *file, const char __user *buf,
size_t size, loff_t *ppos)
{
struct xnvfile_regular *vfile = PDE_DATA(wrap_f_inode(file));
struct xnvfile_input input;
ssize_t ret;
if (vfile->entry.lockops) {
ret = vfile->entry.lockops->get(&vfile->entry);
if (ret)
return ret;
}
input.u_buf = buf;
input.size = size;
input.vfile = &vfile->entry;
ret = vfile->ops->store(&input);
if (vfile->entry.lockops)
vfile->entry.lockops->put(&vfile->entry);
return ret;
}
static struct file_operations vfile_regular_fops = {
.owner = THIS_MODULE,
.open = vfile_regular_open,
.read = seq_read,
.write = vfile_regular_write,
.llseek = seq_lseek,
.release = vfile_regular_release,
};
/**
* @fn int xnvfile_init_regular(const char *name, struct xnvfile_regular *vfile, struct xnvfile_directory *parent)
* @brief Initialize a regular vfile.
*
* @param name The name which should appear in the pseudo-filesystem,
* identifying the vfile entry.
*
* @param vfile A pointer to a vfile descriptor to initialize
* from. The following fields in this structure should be filled in
* prior to call this routine:
*
* - .privsz is the size (in bytes) of the private data area to be
* reserved in the @ref regular_iterator "vfile iterator". A NULL
* value indicates that no private area should be reserved.
*
* - entry.lockops is a pointer to a @ref vfile_lockops "locking
* descriptor", defining the lock and unlock operations for the
* vfile. This pointer may be left to NULL, in which case no
* locking will be applied.
*
* - .ops is a pointer to an @ref regular_ops "operation descriptor".
*
* @param parent A pointer to a virtual directory descriptor; the
* vfile entry will be created into this directory. If NULL, the /proc
* root directory will be used. /proc/rtai is mapped on the
* globally available @a nkvfroot vdir.
*
* @return 0 is returned on success. Otherwise:
*
* - -ENOMEM is returned if the virtual file entry cannot be created
* in the /proc hierarchy.
*/
int xnvfile_init_regular(const char *name,
struct xnvfile_regular *vfile,
struct xnvfile_directory *parent)
{
struct proc_dir_entry *ppde, *pde;
int mode;
if (parent == NULL)
parent = &sysroot;
mode = vfile->ops->store ? 0644 : 0444;
ppde = parent->entry.pde;
pde = proc_create_data(name, mode, ppde, &vfile_regular_fops, vfile);
if (pde == NULL)
return -ENOMEM;
wrap_proc_dir_entry_owner(pde);
vfile->entry.pde = pde;
return 0;
}
EXPORT_SYMBOL_GPL(xnvfile_init_regular);
/**
* @fn int xnvfile_init_dir(const char *name, struct xnvfile_directory *vdir, struct xnvfile_directory *parent)
* @brief Initialize a virtual directory entry.
*
* @param name The name which should appear in the pseudo-filesystem,
* identifying the vdir entry.
*
* @param vdir A pointer to the virtual directory descriptor to
* initialize.
*
* @param parent A pointer to a virtual directory descriptor standing
* for the parent directory of the new vdir. If NULL, the /proc root
* directory will be used. /proc/rtai is mapped on the globally
* available @a nkvfroot vdir.
*
* @return 0 is returned on success. Otherwise:
*
* - -ENOMEM is returned if the virtual directory entry cannot be
* created in the /proc hierarchy.
*/
int xnvfile_init_dir(const char *name,
struct xnvfile_directory *vdir,
struct xnvfile_directory *parent)
{
struct proc_dir_entry *ppde, *pde;
if (parent == NULL)
parent = &sysroot;
ppde = parent->entry.pde;
pde = proc_mkdir(name, ppde);
if (pde == NULL)
return -ENOMEM;
vdir->entry.pde = pde;
vdir->entry.lockops = NULL;
vdir->entry.private = NULL;
wrap_proc_dir_entry_owner(pde);
return 0;
}
EXPORT_SYMBOL_GPL(xnvfile_init_dir);
/**
* @fn int xnvfile_init_link(const char *from, const char *to, struct xnvfile_link *vlink, struct xnvfile_directory *parent)
* @brief Initialize a virtual link entry.
*
* @param from The name which should appear in the pseudo-filesystem,
* identifying the vlink entry.
*
* @param to The target file name which should be referred to
* symbolically by @a name.
*
* @param vlink A pointer to the virtual link descriptor to
* initialize.
*
* @param parent A pointer to a virtual directory descriptor standing
* for the parent directory of the new vlink. If NULL, the /proc root
* directory will be used. /proc/rtai is mapped on the globally
* available @a nkvfroot vdir.
*
* @return 0 is returned on success. Otherwise:
*
* - -ENOMEM is returned if the virtual link entry cannot be created
* in the /proc hierarchy.
*/
int xnvfile_init_link(const char *from,
const char *to,
struct xnvfile_link *vlink,
struct xnvfile_directory *parent)
{
struct proc_dir_entry *ppde, *pde;
if (parent == NULL)
parent = &sysroot;
ppde = parent->entry.pde;
pde = proc_symlink(from, ppde, to);
if (pde == NULL)
return -ENOMEM;
vlink->entry.pde = pde;
vlink->entry.lockops = NULL;
vlink->entry.private = NULL;
wrap_proc_dir_entry_owner(pde);
return 0;
}
EXPORT_SYMBOL_GPL(xnvfile_init_link);
/**
* @fn void xnvfile_destroy(struct xnvfile *vfile)
* @brief Removes a virtual file entry.
*
* @param vfile A pointer to the virtual file descriptor to
* remove.
*/
void xnvfile_destroy(struct xnvfile *vfile)
{
proc_remove(vfile->pde);
}
EXPORT_SYMBOL_GPL(xnvfile_destroy);
/**
* @fn ssize_t xnvfile_get_blob(struct xnvfile_input *input, void *data, size_t size)
* @brief Read in a data bulk written to the vfile.
*
* When writing to a vfile, the associated store() handler from the
* @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
* "regular vfile" is called, with a single argument describing the
* input data. xnvfile_get_blob() retrieves this data as an untyped
* binary blob, and copies it back to the caller's buffer.
*
* @param input A pointer to the input descriptor passed to the
* store() handler.
*
* @param data The address of the destination buffer to copy the input
* data to.
*
* @param size The maximum number of bytes to copy to the destination
* buffer. If @a size is larger than the actual data size, the input
* is truncated to @a size.
*
* @return The number of bytes read and copied to the destination
* buffer upon success. Otherwise, a negative error code is returned:
*
* - -EFAULT indicates an invalid source buffer address.
*/
ssize_t xnvfile_get_blob(struct xnvfile_input *input,
void *data, size_t size)
{
ssize_t nbytes = input->size;
if (nbytes > size)
nbytes = size;
if (nbytes > 0 && copy_from_user(data, input->u_buf, nbytes))
return -EFAULT;
return nbytes;
}
EXPORT_SYMBOL_GPL(xnvfile_get_blob);
/**
* @fn ssize_t xnvfile_get_string(struct xnvfile_input *input, char *s, size_t maxlen)
* @brief Read in a C-string written to the vfile.
*
* When writing to a vfile, the associated store() handler from the
* @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
* "regular vfile" is called, with a single argument describing the
* input data. xnvfile_get_string() retrieves this data as a
* null-terminated character string, and copies it back to the
* caller's buffer.
*
* @param input A pointer to the input descriptor passed to the
* store() handler.
*
* @param s The address of the destination string buffer to copy the
* input data to.
*
* @param maxlen The maximum number of bytes to copy to the
* destination buffer, including the ending null character. If @a
* maxlen is larger than the actual string length, the input is
* truncated to @a maxlen.
*
* @return The number of characters read and copied to the destination
* buffer upon success. Otherwise, a negative error code is returned:
*
* - -EFAULT indicates an invalid source buffer address.
*/
ssize_t xnvfile_get_string(struct xnvfile_input *input,
char *s, size_t maxlen)
{
ssize_t nbytes;
if (maxlen < 1)
return -EINVAL;
nbytes = xnvfile_get_blob(input, s, maxlen - 1);
if (nbytes < 0)
return nbytes;
if (nbytes > 0 && s[nbytes - 1] == '\n')
nbytes--;
s[nbytes] = '\0';
return nbytes;
}
EXPORT_SYMBOL_GPL(xnvfile_get_string);
/**
* @fn ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp)
* @brief Evaluate the string written to the vfile as a long integer.
*
* When writing to a vfile, the associated store() handler from the
* @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
* "regular vfile" is called, with a single argument describing the
* input data. xnvfile_get_integer() retrieves and interprets this
* data as a long integer, and copies the resulting value back to @a
* valp.
*
* The long integer can be expressed in decimal, octal or hexadecimal
* bases depending on the prefix found.
*
* @param input A pointer to the input descriptor passed to the
* store() handler.
*
* @param valp The address of a long integer variable to receive the
* value.
*
* @return The number of characters read while evaluating the input as
* a long integer upon success. Otherwise, a negative error code is
* returned:
*
* - -EINVAL indicates a parse error on the input stream; the written
* text cannot be evaluated as a long integer.
*
* - -EFAULT indicates an invalid source buffer address.
*/
ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp)
{
char *end, buf[32];
ssize_t nbytes;
long val;
nbytes = xnvfile_get_blob(input, buf, sizeof(buf) - 1);
if (nbytes < 0)
return nbytes;
if (nbytes == 0)
return -EINVAL;
buf[nbytes] = '\0';
val = simple_strtol(buf, &end, 0);
if (*end != '\0' && !isspace(*end))
return -EINVAL;
*valp = val;
return nbytes;
}
EXPORT_SYMBOL_GPL(xnvfile_get_integer);
int __vfile_hostlock_get(struct xnvfile *vfile)
{
struct xnvfile_hostlock_class *lc;
lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops);
return down_interruptible(&lc->sem) ? -ERESTARTSYS : 0;
}
EXPORT_SYMBOL_GPL(__vfile_hostlock_get);
void __vfile_hostlock_put(struct xnvfile *vfile)
{
struct xnvfile_hostlock_class *lc;
lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops);
up(&lc->sem);
}
EXPORT_SYMBOL_GPL(__vfile_hostlock_put);
static int __vfile_nklock_get(struct xnvfile *vfile)
{
struct xnvfile_nklock_class *lc;
lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops);
xnlock_get_irqsave(&nklock, lc->s);
return 0;
}
static void __vfile_nklock_put(struct xnvfile *vfile)
{
struct xnvfile_nklock_class *lc;
lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops);
xnlock_put_irqrestore(&nklock, lc->s);
}
struct xnvfile_nklock_class xnvfile_nucleus_lock = {
.ops = {
.get = __vfile_nklock_get,
.put = __vfile_nklock_put,
},
};
int __init xnvfile_init_root(void)
{
struct xnvfile_directory *vdir = &nkvfroot;
struct proc_dir_entry *pde;
pde = proc_mkdir("rtai", NULL);
if (pde == NULL)
return -ENOMEM;
vdir->entry.pde = pde;
vdir->entry.lockops = NULL;
vdir->entry.private = NULL;
wrap_proc_dir_entry_owner(pde);
return 0;
}
void xnvfile_destroy_root(void)
{
nkvfroot.entry.pde = NULL;
remove_proc_entry("rtai", NULL);
}
/*@}*/

View file

@ -1,700 +0,0 @@
/**
* @file
* This file is part of the Xenomai project.
*
* @note Copyright (C) 2010 Philippe Gerum <rpm@xenomai.org>
*
* adapted to RTAI by 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.
*
* @ingroup vfile
*/
#ifndef RTAI_RTDM_VFILE_H
#define RTAI_RTDM_VFILE_H
#ifdef CONFIG_PROC_FS
/** @addtogroup vfile
*@{*/
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <rtdm/xn.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
#define PDE_DATA(inode) PDE(inode)->data
static inline void proc_remove(struct proc_dir_entry *pde)
{
remove_proc_entry(pde->name, pde->parent);
}
#endif
#define wrap_f_inode(file) ((file)->f_path.dentry->d_inode)
#define wrap_proc_dir_entry_owner(entry) do { (void)entry; } while(0)
struct xnvfile_directory;
struct xnvfile_regular_iterator;
struct xnvfile_snapshot_iterator;
struct xnvfile_lock_ops;
struct xnvfile {
struct proc_dir_entry *pde;
struct file *file;
struct xnvfile_lock_ops *lockops;
int refcnt;
void *private;
};
/**
* @brief Vfile locking operations
* @anchor vfile_lockops
*
* This structure describes the operations to be provided for
* implementing locking support on vfiles. They apply to both
* snapshot-driven and regular vfiles.
*/
struct xnvfile_lock_ops {
/**
* @anchor lockops_get
* This handler should grab the desired lock.
*
* @param vfile A pointer to the virtual file which needs
* locking.
*
* @return zero should be returned if the call
* succeeds. Otherwise, a negative error code can be returned;
* upon error, the current vfile operation is aborted, and the
* user-space caller is passed back the error value.
*/
int (*get)(struct xnvfile *vfile);
/**
* @anchor lockops_put This handler should release the lock
* previously grabbed by the @ref lockops_get "get() handler".
*
* @param vfile A pointer to the virtual file which currently
* holds the lock to release.
*/
void (*put)(struct xnvfile *vfile);
};
/*
* XXX: struct semaphore is legacy for mutual exclusion, but supported
* on both 2.4 and 2.6 kernels. Will be changed to mutex when 2.4
* support is dropped from RTAI.
*/
struct xnvfile_hostlock_class {
struct xnvfile_lock_ops ops;
struct semaphore sem;
};
struct xnvfile_nklock_class {
struct xnvfile_lock_ops ops;
spl_t s;
};
struct xnvfile_input {
const char __user *u_buf;
size_t size;
struct xnvfile *vfile;
};
/**
* @brief Regular vfile operation descriptor
* @anchor regular_ops
*
* This structure describes the operations available with a regular
* vfile. It defines handlers for sending back formatted kernel data
* upon a user-space read request, and for obtaining user data upon a
* user-space write request.
*/
struct xnvfile_regular_ops {
/**
* @anchor regular_rewind This handler is called only once,
* when the virtual file is opened, before the @ref
* regular_begin "begin() handler" is invoked.
*
* @param it A pointer to the vfile iterator which will be
* used to read the file contents.
*
* @return Zero should be returned upon success. Otherwise, a
* negative error code aborts the operation, and is passed
* back to the reader.
*
* @note This handler is optional. It should not be used to
* allocate resources but rather to perform consistency
* checks, since no closure call is issued in case the open
* sequence eventually fails.
*/
int (*rewind)(struct xnvfile_regular_iterator *it);
/**
* @anchor regular_begin
* This handler should prepare for iterating over the records
* upon a read request, starting from the specified position.
*
* @param it A pointer to the current vfile iterator. On
* entry, it->pos is set to the (0-based) position of the
* first record to output. This handler may be called multiple
* times with different position requests.
*
* @return A pointer to the first record to format and output,
* to be passed to the @ref regular_show "show() handler" as
* its @a data parameter, if the call succeeds. Otherwise:
*
* - NULL in case no record is available, in which case the
* read operation will terminate immediately with no output.
*
* - VFILE_SEQ_START, a special value indicating that @ref
* regular_show "the show() handler" should receive a NULL
* data pointer first, in order to output a header.
*
* - ERR_PTR(errno), where errno is a negative error code;
* upon error, the current operation will be aborted
* immediately.
*
* @note This handler is optional; if none is given in the
* operation descriptor (i.e. NULL value), the @ref
* regular_show "show() handler()" will be called only once
* for a read operation, with a NULL @a data parameter. This
* particular setting is convenient for simple regular vfiles
* having a single, fixed record to output.
*/
void *(*begin)(struct xnvfile_regular_iterator *it);
/**
* @anchor regular_next
* This handler should return the address of the next record
* to format and output by the @ref regular_show "show()
* handler".
*
* @param it A pointer to the current vfile iterator. On
* entry, it->pos is set to the (0-based) position of the
* next record to output.
*
* @return A pointer to the next record to format and output,
* to be passed to the @ref regular_show "show() handler" as
* its @a data parameter, if the call succeeds. Otherwise:
*
* - NULL in case no record is available, in which case the
* read operation will terminate immediately with no output.
*
* - ERR_PTR(errno), where errno is a negative error code;
* upon error, the current operation will be aborted
* immediately.
*
* @note This handler is optional; if none is given in the
* operation descriptor (i.e. NULL value), the read operation
* will stop after the first invocation of the @ref regular_show
* "show() handler".
*/
void *(*next)(struct xnvfile_regular_iterator *it);
/**
* @anchor regular_end
* This handler is called after all records have been output.
*
* @param it A pointer to the current vfile iterator.
*
* @note This handler is optional and the pointer may be NULL.
*/
void (*end)(struct xnvfile_regular_iterator *it);
/**
* @anchor regular_show
* This handler should format and output a record.
*
* xnvfile_printf(), xnvfile_write(), xnvfile_puts() and
* xnvfile_putc() are available to format and/or emit the
* output. All routines take the iterator argument @a it as
* their first parameter.
*
* @param it A pointer to the current vfile iterator.
*
* @param data A pointer to the record to format then
* output. The first call to the handler may receive a NULL @a
* data pointer, depending on the presence and/or return of a
* @ref regular_begin "hander"; the show handler should test
* this special value to output any header that fits, prior to
* receiving more calls with actual records.
*
* @return zero if the call succeeds, also indicating that the
* handler should be called for the next record if
* any. Otherwise:
*
* - A negative error code. This will abort the output phase,
* and return this status to the reader.
*
* - VFILE_SEQ_SKIP, a special value indicating that the
* current record should be skipped and will not be output.
*/
int (*show)(struct xnvfile_regular_iterator *it, void *data);
/**
* @anchor regular_store
* This handler receives data written to the vfile, likely for
* updating some kernel setting, or triggering any other
* action which fits. This is the only handler which deals
* with the write-side of a vfile. It is called when writing
* to the /proc entry of the vfile from a user-space process.
*
* The input data is described by a descriptor passed to the
* handler, which may be subsequently passed to parsing helper
* routines. For instance, xnvfile_get_string() will accept
* the input descriptor for returning the written data as a
* null-terminated character string. On the other hand,
* xnvfile_get_integer() will attempt to return a long integer
* from the input data.
*
* @param input A pointer to an input descriptor. It refers to
* an opaque data from the handler's standpoint.
*
* @return the number of bytes read from the input descriptor
* if the call succeeds. Otherwise, a negative error code.
* Return values from parsing helper routines are commonly
* passed back to the caller by the @ref store
* "store() handler".
*
* @note This handler is optional, and may be omitted for
* read-only vfiles.
*/
ssize_t (*store)(struct xnvfile_input *input);
};
struct xnvfile_regular {
struct xnvfile entry;
size_t privsz;
struct xnvfile_regular_ops *ops;
};
struct xnvfile_regular_template {
size_t privsz;
struct xnvfile_regular_ops *ops;
struct xnvfile_lock_ops *lockops;
};
/**
* @brief Regular vfile iterator
* @anchor regular_iterator
*
* This structure defines an iterator over a regular vfile.
*/
struct xnvfile_regular_iterator {
/** Current record position while iterating. */
loff_t pos;
/** Backlink to the host sequential file supporting the vfile. */
struct seq_file *seq;
/** Backlink to the vfile being read. */
struct xnvfile_regular *vfile;
/**
* Start of private area. Use xnvfile_iterator_priv() to
* address it.
*/
char private[0];
};
/**
* @brief Snapshot vfile operation descriptor
* @anchor snapshot_ops
*
* This structure describes the operations available with a
* snapshot-driven vfile. It defines handlers for returning a
* printable snapshot of some RTAI object contents upon a
* user-space read request, and for updating this object upon a
* user-space write request.
*/
struct xnvfile_snapshot_ops {
/**
* @anchor snapshot_rewind
* This handler (re-)initializes the data collection, moving
* the seek pointer at the first record. When the file
* revision tag is touched while collecting data, the current
* reading is aborted, all collected data dropped, and the
* vfile is eventually rewound.
*
* @param it A pointer to the current snapshot iterator. Two
* useful information can be retrieved from this iterator in
* this context:
*
* - it->vfile is a pointer to the descriptor of the virtual
* file being rewound.
*
* - xnvfile_iterator_priv(it) returns a pointer to the
* private data area, available from the descriptor, which
* size is vfile->privsz. If the latter size is zero, the
* returned pointer is meaningless and should not be used.
*
* @return A negative error code aborts the data collection,
* and is passed back to the reader. Otherwise:
*
* - a strictly positive value is interpreted as the total
* number of records which will be returned by the @ref
* snapshot_next "next() handler" during the data collection
* phase. If no @ref snapshot_begin "begin() handler" is
* provided in the @ref snapshot_ops "operation descriptor",
* this value is used to allocate the snapshot buffer
* internally. The size of this buffer would then be
* vfile->datasz * value.
*
* - zero leaves the allocation to the @ref snapshot_begin
* "begin() handler" if present, or indicates that no record
* is to be output in case such handler is not given.
*
* @note This handler is optional; a NULL value indicates that
* nothing needs to be done for rewinding the vfile. It is
* called with the vfile lock held.
*/
int (*rewind)(struct xnvfile_snapshot_iterator *it);
/**
* @anchor snapshot_begin
* This handler should allocate the snapshot buffer to hold
* records during the data collection phase. When specified,
* all records collected via the @ref snapshot_next "next()
* handler" will be written to a cell from the memory area
* returned by begin().
*
* @param it A pointer to the current snapshot iterator.
*
* @return A pointer to the record buffer, if the call
* succeeds. Otherwise:
*
* - NULL in case of allocation error. This will abort the data
* collection, and return -ENOMEM to the reader.
*
* - VFILE_SEQ_EMPTY, a special value indicating that no
* record will be output. In such a case, the @ref
* snapshot_next "next() handler" will not be called, and the
* data collection will stop immediately. However, the @ref
* snapshot_show "show() handler" will still be called once,
* with a NULL data pointer (i.e. header display request).
*
* @note This handler is optional; if none is given, an
* internal allocation depending on the value returned by the
* @ref snapshot_rewind "rewind() handler" can be obtained.
*/
void *(*begin)(struct xnvfile_snapshot_iterator *it);
/**
* @anchor snapshot_end
* This handler releases the memory buffer previously obtained
* from begin(). It is usually called after the snapshot data
* has been output by show(), but it may also be called before
* rewinding the vfile after a revision change, to release the
* dropped buffer.
*
* @param it A pointer to the current snapshot iterator.
*
* @param buf A pointer to the buffer to release.
*
* @note This routine is optional and the pointer may be
* NULL. It is not needed upon internal buffer allocation;
* see the description of the @ref snapshot_rewind "rewind()
* handler".
*/
void (*end)(struct xnvfile_snapshot_iterator *it, void *buf);
/**
* @anchor snapshot_next
* This handler fetches the next record, as part of the
* snapshot data to be sent back to the reader via the
* show().
*
* @param it A pointer to the current snapshot iterator.
*
* @param data A pointer to the record to fill in.
*
* @return a strictly positive value, if the call succeeds and
* leaves a valid record into @a data, which should be passed
* to the @ref snapshot_show "show() handler()" during the
* formatting and output phase. Otherwise:
*
* - A negative error code. This will abort the data
* collection, and return this status to the reader.
*
* - VFILE_SEQ_SKIP, a special value indicating that the
* current record should be skipped. In such a case, the @a
* data pointer is not advanced to the next position before
* the @ref snapshot_next "next() handler" is called anew.
*
* @note This handler is called with the vfile lock
* held. Before each invocation of this handler, the vfile
* core checks whether the revision tag has been touched, in
* which case the data collection is restarted from scratch. A
* data collection phase succeeds whenever all records can be
* fetched via the @ref snapshot_next "next() handler", while
* the revision tag remains unchanged, which indicates that a
* consistent snapshot of the object state was taken.
*/
int (*next)(struct xnvfile_snapshot_iterator *it, void *data);
/**
* @anchor snapshot_show
* This handler should format and output a record from the
* collected data.
*
* xnvfile_printf(), xnvfile_write(), xnvfile_puts() and
* xnvfile_putc() are available to format and/or emit the
* output. All routines take the iterator argument @a it as
* their first parameter.
*
* @param it A pointer to the current snapshot iterator.
*
* @param data A pointer to the record to format then
* output. The first call to the handler is always passed a
* NULL @a data pointer; the show handler should test this
* special value to output any header that fits, prior to
* receiving more calls with actual records.
*
* @return zero if the call succeeds, also indicating that the
* handler should be called for the next record if
* any. Otherwise:
*
* - A negative error code. This will abort the output phase,
* and return this status to the reader.
*
* - VFILE_SEQ_SKIP, a special value indicating that the
* current record should be skipped and will not be output.
*/
int (*show)(struct xnvfile_snapshot_iterator *it, void *data);
/**
* @anchor snapshot_store
* This handler receives data written to the vfile, likely for
* updating the associated RTAI object's state, or
* triggering any other action which fits. This is the only
* handler which deals with the write-side of a vfile. It is
* called when writing to the /proc entry of the vfile
* from a user-space process.
*
* The input data is described by a descriptor passed to the
* handler, which may be subsequently passed to parsing helper
* routines. For instance, xnvfile_get_string() will accept
* the input descriptor for returning the written data as a
* null-terminated character string. On the other hand,
* xnvfile_get_integer() will attempt to return a long integer
* from the input data.
*
* @param input A pointer to an input descriptor. It refers to
* an opaque data from the handler's standpoint.
*
* @return the number of bytes read from the input descriptor
* if the call succeeds. Otherwise, a negative error code.
* Return values from parsing helper routines are commonly
* passed back to the caller by the @ref snapshot_store
* "store() handler".
*
* @note This handler is optional, and may be omitted for
* read-only vfiles.
*/
ssize_t (*store)(struct xnvfile_input *input);
};
/**
* @brief Snapshot revision tag
* @anchor revision_tag
*
* This structure defines a revision tag to be used with @ref
* snapshot_vfile "snapshot-driven vfiles".
*/
struct xnvfile_rev_tag {
/** Current revision number. */
int rev;
};
struct xnvfile_snapshot_template {
size_t privsz;
size_t datasz;
struct xnvfile_rev_tag *tag;
struct xnvfile_snapshot_ops *ops;
struct xnvfile_lock_ops *lockops;
};
/**
* @brief Snapshot vfile descriptor
* @anchor snapshot_vfile
*
* This structure describes a snapshot-driven vfile. Reading from
* such a vfile involves a preliminary data collection phase under
* lock protection, and a subsequent formatting and output phase of
* the collected data records. Locking is done in a way that does not
* increase worst-case latency, regardless of the number of records to
* be collected for output.
*/
struct xnvfile_snapshot {
struct xnvfile entry;
size_t privsz;
size_t datasz;
struct xnvfile_rev_tag *tag;
struct xnvfile_snapshot_ops *ops;
};
/**
* @brief Snapshot-driven vfile iterator
* @anchor snapshot_iterator
*
* This structure defines an iterator over a snapshot-driven vfile.
*/
struct xnvfile_snapshot_iterator {
/** Number of collected records. */
int nrdata;
/** Address of record buffer. */
caddr_t databuf;
/** Backlink to the host sequential file supporting the vfile. */
struct seq_file *seq;
/** Backlink to the vfile being read. */
struct xnvfile_snapshot *vfile;
/** Buffer release handler. */
void (*endfn)(struct xnvfile_snapshot_iterator *it, void *buf);
/**
* Start of private area. Use xnvfile_iterator_priv() to
* address it.
*/
char private[0];
};
struct xnvfile_directory {
struct xnvfile entry;
};
struct xnvfile_link {
struct xnvfile entry;
};
/* vfile.begin()=> */
#define VFILE_SEQ_EMPTY ((void *)-1)
/* =>vfile.show() */
#define VFILE_SEQ_START SEQ_START_TOKEN
/* vfile.next/show()=> */
#define VFILE_SEQ_SKIP 2
#define xnvfile_printf(it, args...) seq_printf((it)->seq, ##args)
#define xnvfile_write(it, data, len) seq_write((it)->seq, (data),(len))
#define xnvfile_puts(it, s) seq_puts((it)->seq, (s))
#define xnvfile_putc(it, c) seq_putc((it)->seq, (c))
static inline void xnvfile_touch_tag(struct xnvfile_rev_tag *tag)
{
tag->rev++;
}
static inline void xnvfile_touch(struct xnvfile_snapshot *vfile)
{
xnvfile_touch_tag(vfile->tag);
}
#define xnvfile_noentry \
{ \
.pde = NULL, \
.private = NULL, \
.file = NULL, \
.refcnt = 0, \
}
#define xnvfile_nodir { .entry = xnvfile_noentry }
#define xnvfile_nolink { .entry = xnvfile_noentry }
#define xnvfile_nofile { .entry = xnvfile_noentry }
#define xnvfile_priv(e) ((e)->entry.private)
#define xnvfile_nref(e) ((e)->entry.refcnt)
#define xnvfile_file(e) ((e)->entry.file)
#define xnvfile_iterator_priv(it) ((void *)(&(it)->private))
extern struct xnvfile_nklock_class xnvfile_nucleus_lock;
extern struct xnvfile_directory nkvfroot;
int xnvfile_init_root(void);
void xnvfile_destroy_root(void);
#ifdef __cplusplus
extern "C" {
#endif
int xnvfile_init_snapshot(const char *name,
struct xnvfile_snapshot *vfile,
struct xnvfile_directory *parent);
int xnvfile_init_regular(const char *name,
struct xnvfile_regular *vfile,
struct xnvfile_directory *parent);
int xnvfile_init_dir(const char *name,
struct xnvfile_directory *vdir,
struct xnvfile_directory *parent);
int xnvfile_init_link(const char *from,
const char *to,
struct xnvfile_link *vlink,
struct xnvfile_directory *parent);
void xnvfile_destroy(struct xnvfile *vfile);
ssize_t xnvfile_get_blob(struct xnvfile_input *input,
void *data, size_t size);
ssize_t xnvfile_get_string(struct xnvfile_input *input,
char *s, size_t maxlen);
ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp);
int __vfile_hostlock_get(struct xnvfile *vfile);
void __vfile_hostlock_put(struct xnvfile *vfile);
#ifdef __cplusplus
}
#endif
static inline
void xnvfile_destroy_snapshot(struct xnvfile_snapshot *vfile)
{
xnvfile_destroy(&vfile->entry);
}
static inline
void xnvfile_destroy_regular(struct xnvfile_regular *vfile)
{
xnvfile_destroy(&vfile->entry);
}
static inline
void xnvfile_destroy_dir(struct xnvfile_directory *vdir)
{
xnvfile_destroy(&vdir->entry);
}
static inline
void xnvfile_destroy_link(struct xnvfile_link *vlink)
{
xnvfile_destroy(&vlink->entry);
}
#define DEFINE_VFILE_HOSTLOCK(name) \
struct xnvfile_hostlock_class name = { \
.ops = { \
.get = __vfile_hostlock_get, \
.put = __vfile_hostlock_put, \
}, \
.sem = __SEMAPHORE_INITIALIZER(name.sem, 1), \
}
#else /* !CONFIG_PROC_FS */
#define xnvfile_touch_tag(tag) do { } while (0)
#define xnvfile_touch(vfile) do { } while (0)
#endif /* !CONFIG_PROC_FS */
/*@}*/
#endif /* !RTAI_RTDM_VFILE_H */

View file

@ -1,13 +0,0 @@
#!/bin/sh
srcdir=`dirname "$0"`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd "$srcdir"
autoreconf -v --install || exit 1
cd $ORIGDIR || exit $?
# Do a temporary configure to generate initial makefiles
"$srcdir"/configure --with-linux-dir="/lib/modules/$(uname -r)/build" "$@"

View file

@ -12,12 +12,26 @@ 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

View file

@ -1,4 +1,30 @@
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)
@ -6,3 +32,5 @@ modext = @RTAI_MODULE_EXT@
rtai_hal$(modext):
@(cd $(ARCHDIR)/hal && make rtai_hal$(modext))
#EXTRA_DIST = x86/patches

View file

@ -0,0 +1,3 @@
SUBDIRS = hal
EXTRA_DIST = Kconfig defconfig patches

538
base/arch/arm/Kconfig Normal file
View file

@ -0,0 +1,538 @@
mainmenu "RTAI/ARM configuration"
config MODULES
bool
default y
config RTAI_VERSION
string
default "magma"
menu "General"
config RTAI_INSTALLDIR
string "Installation directory"
default "/usr/realtime"
help
This option defines the directory where the various RTAI
files will be installed on your target system.
This directory may be changed if you double-click in the area
named "Value". The default installation directory is
/usr/realtime.
config RTAI_LINUXDIR
string "Linux source tree"
default "/usr/src/linux"
help
This variable contains the directory of your previously
patched Linux kernel. As explained before, you can changed the
value of the Linux source tree which is fixed by default to
/usr/src/linux.
menu "RTAI Documentation"
config RTAI_DOX_DOC
bool "Build RTAI Doxygen documentation (HTML)"
default n
help
This option causes the Doxygen-based RTAI documentation to be
built. This option is intended for people actually writing
documentation and who want to update the pre-built manuals,
regular users can just use the latter directly. You will need
the Doxygen toolsuite for regenerating the documentation.
config RTAI_DOC_LATEX_NONSTOP
bool "Enable LaTeX verbose output"
default n
help
By default, all documentation generated with LaTeX uses the
silent (batchmode) of LaTeX. If this option is enabled, the
verbose (nonstopmode) of LaTeX will be used instead. This
option is mainly intended for people writing RTAI
documentation.
config RTAI_DBX_DOC
bool "Build DocBook XML documentation (HTML/PDF)"
default n
help
This option causes the DocBook XML based RTAI documentation to be
built. This option is intended for people actually writing
documentation and who want to update the pre-built manuals,
regular users can just use the latter directly.
config RTAI_DBX_NET
bool "Let the DocBook XML tools use network"
depends on RTAI_DBX_DOC
default n
help
Let the DocBook tools use internet to fetch the DTD and XSL stylesheets.
If disabled, the documentation generation will fail if the necessary
DTD(s) and XSL stylesheets can not be found on the local computer.
config RTAI_DBX_ROOT
string "Docbook XML root"
depends on RTAI_DBX_DOC
default ""
help
Specify the DocBook XML root (that is, the directory where docbook.dtd
should be taken). Leave blank to let configure try the "well-known"
locations.
config RTAI_DBX_XSL_ROOT
string "Docbook XML XSL stylesheet root"
depends on RTAI_DBX_DOC
default ""
help
Specify the DocBook XML XSL root. Leave blank to let configure try the
"well-known" locations.
endmenu
config RTAI_TESTSUITE
bool "Build RTAI testsuite"
default y
help
Once you are done with the building process of RTAI, it may be
safe to run the testsuite to make sure your RTAI system is
functional.
config RTAI_COMPAT
bool "Enable source compatibility mode"
default y
help
This option allows to preserve the compatibility between
applications issued from the 24.1.x version of RTAI and the
3.x branch. This way, no adaptation in the header files is
required.
config RTAI_EXTENDED
bool "Enable extended configuration mode"
default n
help
Allows some configuration parameters in the Hardware
Abstraction Layer or the schedulers.
config RTAI_KMOD_DEBUG
bool "Enable debug symbols in modules"
depends on RTAI_EXTENDED
default n
help
This options adds the -g flag when compiling
kernel modules.
config RTAI_USER_DEBUG
bool "Enable debug symbols in user-space programs"
depends on RTAI_EXTENDED
default n
help
This options adds the -g flag when compiling user-space
programs. LXRT inlining is also implicitely disabled.
config RTAI_MAINTAINER
bool "Enable maintainer mode"
depends on RTAI_EXTENDED
default n
help
This option will activate the '--enable-maintainer-mode'
option in the configure scripts. For more information, refer
to the autoconf documentation:
http://sources.redhat.com/autobook/autobook/autobook_26.html#SEC26
config RTAI_MAINTAINER_AUTOTOOLS
bool "Enable Autoconf/Automake maintainer mode"
depends on RTAI_MAINTAINER
default n
choice
prompt "Inlining mode of user-space services"
depends on RTAI_EXTENDED
config RTAI_LXRT_EXTERN_INLINE
bool "Conditional inlining"
help
i.e. extern inline. Depends on compiler's optimization switch.
config RTAI_LXRT_STATIC_INLINE
bool "Eager inlining"
help
i.e. static inline. Always inline regardless of compiler's
optimization switch.
config RTAI_LXRT_NO_INLINE
bool "No inlining"
help
Never inline user-space services. This implies linking
client programs against the appropriate support library
(e.g. liblxrt.a for LXRT services).
endchoice
endmenu
menu "Machine (ARM)"
config RTAI_FPU_SUPPORT
bool
default n
help
Currently it is assumed that soft-float or FPU-emulation (i.e. handled
in kernel, triggered via undefined opcode exception). In both cases all
work (initializing FPU, saving registers etc.) is done by the soft-float
library or the FPU-emulation code, respectively. Hence, RTAI doesn't
have to do anything.
config RTAI_CPUS
string
default 1
endmenu
menu "Base system"
config RTAI_SCHED_UP
bool "Scheduler for uniprocessor machine (kernel tasks only)"
default y
help
This option allows you to select the UP realtime scheduler to
be interfaced to the RTAI module. This type of scheduler don't
have to be used on a MP machine.
config RTAI_SCHED_SMP
bool
default n
config RTAI_SCHED_MUP
bool
default n
config RTAI_SCHED_LXRT
bool "LXRT scheduler (kernel and user-space tasks)"
default y
help
LXRT is a user-space interface providing a symmetric API that
may be used by both real-time RTAI tasks and linux
processes. The full range of Linux system calls is then
available and transitions between "soft" real-time and "hard"
real-time can be performed.
As far as scheduling is concerned, LXRT requires the use of
SCHED_FIFO scheduling policy with statically assigned process
priorities to achieve "soft" real-time performance whilst in
user-space. Since LXRT provides the faculty to switch an
application process to real-time, a real-time agent task is
created and executes the real-time services on behalf of the
LXRT process.
The NEWLXRT scheduler unifies U/MP and kernel/user space by
scheduling Linux tasks/kernel threads natively, along with
RTAI kernel tasks, all in one. In fact, NEWLXRT brings
something new: a linux hard real-time application interface
that is totally based on the scheduling of Linux tasks and
kernel threads only. The NEWLXRT implementation doesn't need
any RTAI proper task to be supported.
menu "Scheduler options"
depends on RTAI_EXTENDED
config RTAI_SCHED_ISR_LOCK
bool
default n
config RTAI_SCHED_LXRT_NUMSLOTS
string "Number of LXRT slots"
default 100
endmenu
menu "IPC support"
config RTAI_BITS
tristate "Event flags"
default m
help
Event flags are used to synchronize a task with the occurrence
of multiple events. This synchronization may be disjunctive
when any of the events have occurred or conjunctive when all
events have occured. The former corresponds to a logical OR
whereas the latter is associated to a logical AND. Their use
is similar to semaphores' except that signal/waits are not
related to just a simple counter but depends on the
combination of set of bits.
The module will be called rtai_bits.o.
config RTAI_FIFOS
tristate "Fifo"
default m
help
Originally fifos were used to allow communication between
kernel-space modules and user-space application. Even if
fifos are strictly no more required in RTAI, because of the
availability of LXRT, fifos are kept for both compatibility
reasons and because they are very useful tools to be used to
communicate with interrupt handlers, since they do not require
any scheduler to be installed.
The module will be called rtai_fifos.o.
config RTAI_NETRPC
tristate
default n
config RTAI_NETRPC_RTNET
bool "Emulate RTNet"
depends on RTAI_NETRPC
default y
config RTAI_SHM
tristate
default n
config RTAI_SEM
tristate "Semaphores"
default m
help
A semaphore is a protocol mechanism offered to:
- control access to a shared resource (mutual exclusion);
- signal the occurrence of an event;
- allow two tasks to synchronize their activities.
Resource semaphores can be recursively nested and support full
priority inheritance, both among semaphore resources and
intertask messages, for a singly owned resource.
Priority inheritance becomes an adaptive priority ceiling when
a task owns multiple resources, including messages sent to it.
Both binary and counting semaphores are able to queue tasks
either in FIFO or priority order and this can be chosen
dynamically at run time.
The module will be called rtai_sem.o.
config RTAI_MSG
tristate "Message"
default m
help
The module will be called rtai_msg.o.
config RTAI_MBX
tristate "Mailboxes"
depends on RTAI_SEM
default y if RTAI_SEM=y
default m if RTAI_SEM=m
help
A mailbox corresponds to a pointer-size variable which is
associated to a service provided by the kernel. It allows a
task or an ISR to deposit a message (the pointer) into this
mailbox.
The RTAI mailbox implementation is very flexible as it allows
to send any message size by using any mailbox buffer
size. They are based on the First In First Out (FIFO)
principle and on Last In First Out (LIFO) for urgent delivery.
Mailboxes depend on semaphores.
The module will be called rtai_mbx.o.
config RTAI_TBX
tristate "Typed mailboxes"
depends on RTAI_SEM
default y if RTAI_SEM=y
default m if RTAI_SEM=m
help
Typed mailboxes (TBX) are an alternative to the default RTAI
mailboxes. They offer:
1- message broadcasting allowing to send a message to all the
tasks that are pending on the same TBX;
2- urgent sending of messages: these messages are not
enqueued, but inserted in the head of the queue, bypassing all
the other messages already present in TBX;
3- a priority or fifo wakeup policy that may be set at runtime
when creating the typed mailbox.
Typed mailboxes depend on semaphores.
The module will be called rtai_tbx.o.
config RTAI_MQ
tristate "POSIX-like message queues"
depends on RTAI_SEM
default y if RTAI_SEM=y
default m if RTAI_SEM=m
help
RTAI pqueues implements the message queues section
of the Posix 1003.1d API. They provide kernel-safe message
queues. Message queues depend on semaphores.
The module will be called rtai_mq.o.
endmenu
menu "Other features"
config RTAI_MATH
bool "Math support"
depends on RTAI_FPU_SUPPORT
default y
config RTAI_MATH_C99
bool "C99 standard support"
depends on RTAI_MATH
default n
config RTAI_MALLOC
tristate "Real-time malloc support"
default y
help
RTAI provides a real-time implementation of malloc().
This allows real-time tasks to allocate and to
free memory safely whilst executing in the real-time domain.
The module will be called rtai_malloc.o.
config RTAI_MALLOC_VMALLOC
bool "Use vmalloc() support"
depends on RTAI_EXTENDED && RTAI_MALLOC
default n
help
RTAI's malloc support offers two different ways to allocate
memory chunks.
The reasons for using vmalloc:
- it is simpler to share allocated buffers with user space;
- it doesn't have the size restriction of kmalloc.
The reasons for using kmalloc:
- it is faster;
- it exhibits contiguous buffer addressing needed for DMA
controllers which don't have scattering/gathering capability.
The default is using kmalloc()
config RTAI_MALLOC_HEAPSZ
string "Size of the global heap (Kbytes)"
depends on RTAI_MALLOC
default 128
help
RTAI pre-allocates a global heap as part of its initialization
chores. This parameter allows to define its size (in
kilobytes).
config RTAI_TASKLETS
tristate "Tasklets"
default m
help
The tasklets module adds an interesting new feature along the
line, pioneered by RTAI, of a symmetric usage of all its
services inter-intra kernel and user space for both soft and
hard real-time. The new services provided can be useful when
you have many tasks, both in kernel and user space, that must
execute in hard real-time but do not need any RTAI scheduler
services that could lead to a task block.
Such tasks are called tasklets and can be of two kinds:
- a simple tasklet;
- timed tasklets (timers).
The tasklets implementation of timed tasklets relies on a
server support task that executes the related timer functions,
either in oneshot or periodic mode, on the base of their time
deadline and according to their user assigned priority.
As explained above, plain tasklets are just functions executed
from kernel space. Their execution needs no server and is
simply triggered by calling the user specified tasklet
function at due time, either from a kernel task or interrupt
handler in charge of their execution when they are needed.
The module will be called rtai_tasklets.o.
config RTAI_TRACE
bool "LTT support"
default n
help
Originally, the Linux Trace Toolkit is a suite of tools
designed to extract program execution details from the Linux
operating system and interpret them. Specifically, it enables
to extract processor utilization and allocation information
for a certain period of time. It is then possible to perform
various calculations on this data and dump this in a text
file. This tool is enhanced by a GTK GUI which allows an easy
exploitation of those results. The Linux Trace Toolkit has
been natively integrated into RTAI modules.
You may refer to http://www.opersys.com/LTT/ for more information.
config RTAI_USI
tristate "User-space interrupts"
default m
depends on RTAI_SEM && RTAI_TASKLETS
default y if RTAI_SEM=y || RTAI_TASKLETS=y
default m if RTAI_SEM=m || RTAI_TASKLETS=m
help
RTAI already contains some examples hinting at managing
interrupts in user space, e.g: resumefromintr in lxrt-net_rpc,
pressa in lxrt, but all of them require installing a proper
handler in kernel space to wake up a hard real-time
LXRT/NEWLXRT task.
The user space interrupt support does the same but adds
something that permits you to avoid writing anything in kernel
space.
The module will be called rtai_usi.o.
config RTAI_WD
bool "Watchdog support"
default y
help
The purpose of the watchdog is to provide protection services
to RTAI thereby protecting it (and the host Linux OS) against
programming errors in RTAI applications.
The RTAI module and a scheduler should be mounted to use the
watchdog and once mounted, it will constantly monitor periodic
real-time tasks that already exist, or that are created later.
However this feature is optional and it is assumed that your
RTAI applications are well behaved so that RTAI should behave
the same whether or not you have the watchdog mounted. The
overhead imposed by the watchdog depends on the speed that you
run it, but in most cases should be minimal.
The following watchdog policies are possible:
- do nothing other than log some messages and keep a record of
the bad task;
- resynchronise the task's frame time and nothing more;
- debug policy which is a special case of the above
resynchronisation policy;
- stretch the period of the offending task until it no longer
overruns;
- slip the offending task by forcibly suspending it for a
percentage of its period;
- suspend the offending task so that it no longer threaten the system;
- kill the offending task and remove all traces.
The module will be called rtai_wd.o.
endmenu
endmenu
menu "Add-ons"
config RTAI_CPLUSPLUS
bool
default n
config RTAI_SERIAL
bool "Serial line driver"
default n
help
RTAI provides a real-time serial driver.
The module will be called rtai_serial.o.
endmenu

77
base/arch/arm/defconfig Normal file
View file

@ -0,0 +1,77 @@
#
# Automatically generated make config: don't edit
#
CONFIG_MODULES=y
CONFIG_RTAI_VERSION="3.3 (magma)"
#
# General
#
CONFIG_RTAI_INSTALLDIR="/usr/realtime"
CONFIG_RTAI_LINUXDIR="/usr/src/linux"
#
# RTAI Documentation
#
# CONFIG_RTAI_DOX_DOC is not set
# CONFIG_RTAI_DOC_LATEX_NONSTOP is not set
# CONFIG_RTAI_DBX_DOC is not set
CONFIG_RTAI_TESTSUITE=y
# CONFIG_RTAI_COMPAT is not set
CONFIG_RTAI_EXTENDED=y
CONFIG_RTAI_KMOD_DEBUG=y
CONFIG_RTAI_USER_DEBUG=y
# CONFIG_RTAI_MAINTAINER is not set
CONFIG_RTAI_LXRT_EXTERN_INLINE=y
# CONFIG_RTAI_LXRT_STATIC_INLINE is not set
# CONFIG_RTAI_LXRT_NO_INLINE is not set
#
# Machine (ARM)
#
# CONFIG_RTAI_FPU_SUPPORT is not set
CONFIG_RTAI_CPUS="1"
#
# Base system
#
CONFIG_RTAI_SCHED_UP=y
# CONFIG_RTAI_SCHED_SMP is not set
# CONFIG_RTAI_SCHED_MUP is not set
CONFIG_RTAI_SCHED_LXRT=y
#
# Scheduler options
#
# CONFIG_RTAI_SCHED_ISR_LOCK is not set
CONFIG_RTAI_SCHED_LXRT_NUMSLOTS="100"
#
# IPC support
#
CONFIG_RTAI_BITS=m
CONFIG_RTAI_FIFOS=m
# CONFIG_RTAI_NETRPC is not set
# CONFIG_RTAI_SHM is not set
CONFIG_RTAI_SEM=m
CONFIG_RTAI_MSG=m
CONFIG_RTAI_MBX=m
CONFIG_RTAI_TBX=m
CONFIG_RTAI_MQ=m
#
# Other features
#
CONFIG_RTAI_MALLOC=y
# CONFIG_RTAI_MALLOC_VMALLOC is not set
CONFIG_RTAI_MALLOC_HEAPSZ="128"
CONFIG_RTAI_TASKLETS=m
# CONFIG_RTAI_TRACE is not set
CONFIG_RTAI_USI=m
# CONFIG_RTAI_WD is not set
#
# Add-ons
#
# CONFIG_RTAI_CPLUSPLUS is not set
# CONFIG_RTAI_SERIAL is not set

View file

@ -0,0 +1,63 @@
moduledir = @RTAI_MODULE_DIR@
modext = @RTAI_MODULE_EXT@
CROSS_COMPILE = @CROSS_COMPILE@
libhal_a_SOURCES = hal.c
if CONFIG_ARCH_EP9301
libhal_a_SOURCES += mach-ep9301/ep9301-timer.c
endif
if CONFIG_ARCH_PXA
libhal_a_SOURCES += mach-pxa/pxa-timer.c
endif
if CONFIG_ARCH_AT91
libhal_a_SOURCES += mach-at91/at91-timer.c
endif
if CONFIG_ARCH_IMX
libhal_a_SOURCES += mach-imx/imx-timer.c
endif
if CONFIG_KBUILD
rtai_hal.ko: @RTAI_KBUILD_ENV@
rtai_hal.ko: $(libhal_a_SOURCES)
@RTAI_KBUILD_TOP@ \
@RTAI_KBUILD_CMD@ \
@RTAI_KBUILD_BOTTOM@
clean-local:
@RTAI_KBUILD_CLEAN@
else
noinst_LIBRARIES = libhal.a
libhal_a_AR = $(CROSS_COMPILE)ar cru
INCLUDES = \
@RTAI_KMOD_CFLAGS@ \
-I$(top_srcdir)/base/include \
-I../../../include \
-I../../../..
rtai_hal.o: libhal.a
$(CROSS_COMPILE)$(LD) --whole-archive $< -r -o $@
clean-local:
endif
all-local: rtai_hal$(modext)
if CONFIG_RTAI_OLD_FASHIONED_BUILD
$(mkinstalldirs) $(top_srcdir)/modules
$(INSTALL_DATA) $^ $(top_srcdir)/modules
endif
install-exec-local: rtai_hal$(modext)
$(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $< $(DESTDIR)$(moduledir)
EXTRA_DIST = Makefile.kbuild hal.immed hal.piped

View file

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

1172
base/arch/arm/hal/hal.c Normal file

File diff suppressed because it is too large Load diff

1162
base/arch/arm/hal/hal.immed Normal file

File diff suppressed because it is too large Load diff

854
base/arch/arm/hal/hal.piped Normal file
View file

@ -0,0 +1,854 @@
/*
* ARM RTAI over Adeos -- based on ARTI for x86 and RTHAL for ARM.
*
* Original RTAI/x86 layer implementation:
* Copyright (c) 2000 Paolo Mantegazza (mantegazza@aero.polimi.it)
* Copyright (c) 2000 Steve Papacharalambous (stevep@zentropix.com)
* Copyright (c) 2000 Stuart Hughes
* and others.
*
* RTAI/x86 rewrite over Adeos:
* Copyright (c) 2002 Philippe Gerum (rpm@xenomai.org)
*
* Original RTAI/ARM RTHAL implementation:
* Copyright (c) 2000 Pierre Cloutier (pcloutier@poseidoncontrols.com)
* Copyright (c) 2001 Alex Züpke, SYSGO RTS GmbH (azu@sysgo.de)
* Copyright (c) 2002 Guennadi Liakhovetski DSA GmbH (gl@dsa-ac.de)
* Copyright (c) 2002 Steve Papacharalambous (stevep@zentropix.com)
* Copyright (c) 2002 Wolfgang Müller (wolfgang.mueller@dsa-ac.de)
* Copyright (c) 2003 Bernard Haible, Marconi Communications
* Copyright (c) 2003 Thomas Gleixner (tglx@linutronix.de)
* Copyright (c) 2003 Philippe Gerum (rpm@xenomai.org)
*
* RTAI/ARM over Adeos rewrite:
* Copyright (c) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at)
*
*
* 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.
*/
#include <linux/version.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/stddef.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <asm/mach/irq.h>
#include <asm/proc/ptrace.h>
#define __RTAI_HAL__
#include <asm/rtai_hal.h>
#include <asm/rtai_lxrt.h>
#include <asm/rtai_usi.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <rtai_proc_fs.h>
#endif /* CONFIG_PROC_FS */
#include <rtai_version.h>
MODULE_LICENSE("GPL");
typedef void (*isr_hook_t)(int);
/* global */
struct {
rt_irq_handler_t handler;
void *cookie;
int retmode;
} rtai_realtime_irq[NR_IRQS]
__attribute__((__aligned__(L1_CACHE_BYTES)));
adomain_t rtai_domain;
struct rt_times rt_times;
struct rt_times rt_smp_times[RTAI_NR_CPUS] = { { 0 } };
struct rtai_switch_data rtai_linux_context[RTAI_NR_CPUS];
struct calibration_data rtai_tunables;
volatile unsigned long rtai_cpu_realtime;
volatile unsigned long rtai_cpu_lock;
int rtai_adeos_ptdbase = -1;
long long (*rtai_lxrt_invoke_entry)(unsigned long, void *); /* hook for lxrt calls */
struct { volatile int locked, rqsted; } rt_scheduling[RTAI_NR_CPUS];
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *rtai_proc_root = NULL;
#endif
/* local */
static struct {
unsigned long flags;
int count;
} rtai_linux_irq[NR_IRQS];
static struct {
void (*k_handler)(void);
long long (*u_handler)(unsigned);
unsigned label;
} rtai_sysreq_table[RTAI_NR_SRQS];
static unsigned rtai_sysreq_virq;
static unsigned long rtai_sysreq_map = 3; /* srqs #[0-1] are reserved */
static unsigned long rtai_sysreq_pending;
static unsigned long rtai_sysreq_running;
static spinlock_t rtai_ssrq_lock = SPIN_LOCK_UNLOCKED;
static volatile int rtai_sync_level;
static atomic_t rtai_sync_count = ATOMIC_INIT(1);
static RT_TRAP_HANDLER rtai_trap_handler;
static int (*saved_adeos_syscall_handler)(struct pt_regs *regs);
#ifdef CONFIG_RTAI_SCHED_ISR_LOCK
// *TODO* enable in config, do tests
static isr_hook_t rtai_isr_hook;
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
unsigned long
rtai_critical_enter(void (*synch)(void))
{
unsigned long flags = adeos_critical_enter(synch);
if (atomic_dec_and_test(&rtai_sync_count))
rtai_sync_level = 0;
else if (synch != NULL)
printk(KERN_INFO "RTAI[hal]: warning: nested sync will fail.\n");
return flags;
}
void
rtai_critical_exit(unsigned long flags)
{
atomic_inc(&rtai_sync_count);
adeos_critical_exit(flags);
}
int
rt_request_irq(unsigned irq, rt_irq_handler_t handler, void *cookie, int retmode)
{
unsigned long flags;
if (handler == NULL || irq >= NR_IRQS)
return -EINVAL;
if (rtai_realtime_irq[irq].handler != NULL)
return -EBUSY;
flags = rtai_critical_enter(NULL);
rtai_realtime_irq[irq].handler = handler;
rtai_realtime_irq[irq].cookie = cookie;
rtai_critical_exit(flags);
return 0;
}
int
rt_release_irq(unsigned irq)
{
unsigned long flags;
if (irq >= NR_IRQS || !rtai_realtime_irq[irq].handler)
return -EINVAL;
flags = rtai_critical_enter(NULL);
rtai_realtime_irq[irq].handler = NULL;
rtai_critical_exit(flags);
return 0;
}
void
rt_set_irq_cookie(unsigned irq, void *cookie)
{
if (irq < NR_IRQS)
rtai_realtime_irq[irq].cookie = cookie;
}
/*
* The function below allow you to manipulate the PIC at hand, but you must
* know what you are doing. Such a duty does not pertain to this manual and
* you should refer to your PIC datasheet.
*
* Note that Linux has the same functions, but they must be used only for its
* interrupts. Only the ones below can be safely used in real time handlers.
*
* It must also be remarked that when you install a real time interrupt handler,
* RTAI already calls either rt_mask_and_ack_irq(), for level triggered
* interrupts, or rt_ack_irq(), for edge triggered interrupts, before passing
* control to your interrupt handler. Thus, generally you should just call
* rt_unmask_irq() at due time, for level triggered interrupts, while nothing
* should be done for edge triggered ones. Recall that in the latter case you
* allow also any new interrupts on the same request as soon as you enable
* interrupts at the CPU level.
*
* Often some of the functions below do equivalent things. Once more there is no
* way of doing it right except by knowing the hardware you are manipulating.
* Furthermore you must also remember that when you install a hard real time
* handler the related interrupt is usually disabled, unless you are overtaking
* one already owned by Linux which has been enabled by it. Recall that if
* have done it right, and interrupts do not show up, it is likely you have just
* to rt_enable_irq() your irq.
*
* Note: Adeos already does all the magic that allows to call the
* interrupt controller routines safely.
*/
unsigned
rt_startup_irq(unsigned irq)
{
struct irqdesc *id = &irq_desc[irq];
id->probing = 0;
id->triggered = 0;
id->disable_depth = 0;
id->unmask(irq);
return 0;
}
void
rt_shutdown_irq(unsigned irq)
{
struct irqdesc *id = &irq_desc[irq];
id->disable_depth = (unsigned int)-1;
id->mask(irq);
}
void
rt_enable_irq(unsigned irq)
{
struct irqdesc *id = &irq_desc[irq];
if (id->disable_depth == 0) {
printk(KERN_ERR "RTAI[hal]: %s(%u) unbalanced from %p\n",
__func__, irq, __builtin_return_address(0));
} else if (--id->disable_depth == 0) {
id->probing = 0;
id->unmask(irq);
}
}
void
rt_disable_irq(unsigned irq)
{
struct irqdesc *id = &irq_desc[irq];
if (id->disable_depth++ == 0)
id->mask(irq);
}
void
rt_mask_and_ack_irq(unsigned irq)
{
irq_desc[irq].mask_ack(irq);
}
void
rt_unmask_irq(unsigned irq)
{
irq_desc[irq].unmask(irq);
}
void
rt_ack_irq(unsigned irq)
{
/* ARM has no "ack" slot in irqdesc, do mask_ack and then unmask */
struct irqdesc *id = &irq_desc[irq];
id->mask_ack(irq);
id->unmask(irq);
}
/**
* Install shared Linux interrupt handler.
*
* rt_request_linux_irq installs function @a handler as a standard Linux
* interrupt service routine for IRQ level @a irq forcing Linux to share the IRQ
* with other interrupt handlers, even if it does not want. The handler is
* appended to any already existing Linux handler for the same irq and is run by
* Linux irq as any of its handler. In this way a real time application can
* monitor Linux interrupts handling at its will. The handler appears in
* /proc/interrupts.
*
* @param handler pointer on the interrupt service routine to be installed.
*
* @param name is a name for /proc/interrupts.
*
* @param dev_id is to pass to the interrupt handler, in the same way as the
* standard Linux irq request call.
*
* The interrupt service routine can be uninstalled with rt_free_linux_irq().
*
* @retval 0 on success.
* @retval EINVAL if @a irq is not a valid IRQ number or handler is @c NULL.
* @retval EBUSY if there is already a handler of interrupt @a irq.
*/
int
rt_request_linux_irq(unsigned irq,
irqreturn_t (*handler)(int irq, void *dev_id, struct pt_regs *regs),
char *name,
void *dev_id)
{
unsigned long flags;
if (irq >= NR_IRQS || !handler)
return -EINVAL;
rtai_save_flags_and_cli(flags);
if (rtai_linux_irq[irq].count++ == 0 && irq_desc[irq].action) {
rtai_linux_irq[irq].flags = irq_desc[irq].action->flags;
irq_desc[irq].action->flags |= SA_SHIRQ;
}
rtai_restore_flags(flags);
request_irq(irq, handler, SA_SHIRQ, name, dev_id);
return 0;
}
/**
* Uninstall shared Linux interrupt handler.
*
* @param dev_id is to pass to the interrupt handler, in the same way as the
* standard Linux irq request call.
*
* @param irq is the IRQ level of the interrupt handler to be freed.
*
* @retval 0 on success.
* @retval EINVAL if @a irq is not a valid IRQ number.
*/
int
rt_free_linux_irq(unsigned irq, void *dev_id)
{
unsigned long flags;
if (irq >= NR_IRQS || rtai_linux_irq[irq].count == 0)
return -EINVAL;
rtai_save_flags_and_cli(flags);
free_irq(irq, dev_id);
if (--rtai_linux_irq[irq].count == 0 && irq_desc[irq].action)
irq_desc[irq].action->flags = rtai_linux_irq[irq].flags;
rtai_restore_flags(flags);
return 0;
}
/**
* Pend an IRQ to Linux.
*
* rt_pend_linux_irq appends a Linux interrupt irq for processing in Linux IRQ
* mode, i.e. with hardware interrupts fully enabled.
*
* @note rt_pend_linux_irq does not perform any check on @a irq.
*/
void
rt_pend_linux_irq(unsigned irq)
{
adeos_propagate_irq(irq);
}
/**
* Install a system request handler
*
* rt_request_srq installs a two way RTAI system request (srq) by assigning
* @a u_handler, a function to be used when a user calls srq from user space,
* and @a k_handler, the function to be called in kernel space following its
* activation by a call to rt_pend_linux_srq(). @a k_handler is in practice
* used to request a service from the kernel. In fact Linux system requests
* cannot be used safely from RTAI so you can setup a handler that receives real
* time requests and safely executes them when Linux is running.
*
* @param u_handler can be used to effectively enter kernel space without the
* overhead and clumsiness of standard Unix/Linux protocols. This is very
* flexible service that allows you to personalize your use of RTAI.
*
* @return the number of the assigned system request on success.
* @retval EINVAL if @a k_handler is @c NULL.
* @retval EBUSY if no free srq slot is available.
*/
int
rt_request_srq(unsigned label, void (*k_handler)(void), long long (*u_handler)(unsigned))
{
unsigned long flags;
int srq;
if (k_handler == NULL)
return -EINVAL;
rtai_save_flags_and_cli(flags);
if (rtai_sysreq_map != ~0) {
srq = ffz(rtai_sysreq_map);
set_bit(srq, &rtai_sysreq_map);
rtai_sysreq_table[srq].k_handler = k_handler;
rtai_sysreq_table[srq].u_handler = u_handler;
rtai_sysreq_table[srq].label = label;
} else
srq = -EBUSY;
rtai_restore_flags(flags);
return srq;
}
/**
* Uninstall a system request handler
*
* rt_free_srq uninstalls the specified system call @a srq, returned by
* installing the related handler with a previous call to rt_request_srq().
*
* @retval EINVAL if @a srq is invalid.
*/
int
rt_free_srq(unsigned srq)
{
return (srq < 2 || srq >= RTAI_NR_SRQS || !test_and_clear_bit(srq, &rtai_sysreq_map))
? -EINVAL
: 0;
}
/**
* Append a Linux IRQ.
*
* rt_pend_linux_srq appends a system call request srq to be used as a service
* request to the Linux kernel.
*
* @param srq is the value returned by rt_request_srq.
*
* @note rt_pend_linux_srq does not perform any check on irq.
*/
void
rt_pend_linux_srq(unsigned srq)
{
int cpuid;
if (srq > 0 && srq < RTAI_NR_SRQS) {
set_bit(srq, &rtai_sysreq_pending);
cpuid = rtai_cpuid();
if (adp_cpu_current[cpuid] == &rtai_domain)
adeos_propagate_irq(rtai_sysreq_virq);
else
adeos_schedule_irq(rtai_sysreq_virq);
}
}
/* rt_request_timer(): install a timer interrupt handler and set hardware-timer
* to requested period. This is arch-specific (stopping/reprogramming/...
* timer). Hence, the function is contained in mach-ARCH/ARCH-timer.c
*/
/* rt_free_timer(): uninstall a timer handler previously set by
* rt_request_timer() and reset hardware-timer to Linux HZ-tick.
* This is arch-specific (stopping/reprogramming/... timer).
* Hence, the function is contained in mach-ARCH/ARCH-timer.c
*/
RT_TRAP_HANDLER
rt_set_trap_handler(RT_TRAP_HANDLER handler)
{
return (RT_TRAP_HANDLER)xchg(&rtai_trap_handler, handler);
}
static void
rtai_irq_trampoline(unsigned irq)
{
TRACE_RTAI_GLOBAL_IRQ_ENTRY(irq, 0);
if (rtai_realtime_irq[irq].handler)
{
#ifdef CONFIG_RTAI_SCHED_ISR_LOCK
adeos_declare_cpuid;
adeos_load_cpuid();
if (!rt_scheduling[cpuid].locked++)
rt_scheduling[cpuid].rqsted = 0;
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
rtai_realtime_irq[irq].handler(irq, rtai_realtime_irq[irq].cookie);
#ifdef CONFIG_RTAI_SCHED_ISR_LOCK
if (rt_scheduling[cpuid].locked && !(--rt_scheduling[cpuid].locked))
if (rt_scheduling[cpuid].rqsted > 0 && rtai_isr_hook)
rtai_isr_hook(cpuid);
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
}
else
adeos_propagate_irq(irq);
TRACE_RTAI_GLOBAL_IRQ_EXIT();
}
static void
rtai_trap_fault(adevinfo_t *evinfo)
{
adeos_declare_cpuid;
TRACE_RTAI_TRAP_ENTRY(evinfo->event, 0);
if (evinfo->domid != RTAI_DOMAIN_ID)
goto propagate;
adeos_load_cpuid();
/* We don't treat SIGILL as "FPU usage" as there is no FPU support in RTAI for ARM.
* *FIXME* The whole FPU kernel emulation issue has to be sorted out (is it
* reentrentant, do we need to save the emulated registers, can it be used
* in kernel space, etc.). */
if (rtai_trap_handler != NULL
&& rtai_trap_handler(evinfo->event, evinfo->event, (struct pt_regs *)evinfo->evdata,
(void *)cpuid) != 0)
goto endtrap;
propagate:
adeos_propagate_event(evinfo);
endtrap:
TRACE_RTAI_TRAP_EXIT();
}
static void
rtai_ssrq_trampoline(unsigned virq)
{
unsigned long pending;
spin_lock(&rtai_ssrq_lock);
while ((pending = rtai_sysreq_pending & ~rtai_sysreq_running) != 0) {
unsigned srq = ffnz(pending);
set_bit(srq, &rtai_sysreq_running);
clear_bit(srq, &rtai_sysreq_pending);
spin_unlock(&rtai_ssrq_lock);
if (test_bit(srq, &rtai_sysreq_map))
rtai_sysreq_table[srq].k_handler();
clear_bit(srq, &rtai_sysreq_running);
spin_lock(&rtai_ssrq_lock);
}
spin_unlock(&rtai_ssrq_lock);
}
extern inline long long
rtai_usrq_trampoline(unsigned long srq, unsigned long label)
{
long long r = 0;
TRACE_RTAI_SRQ_ENTRY(srq, label);
if (srq > 1 && srq < RTAI_NR_SRQS
&& test_bit(srq, &rtai_sysreq_map)
&& rtai_sysreq_table[srq].u_handler != NULL)
r = rtai_sysreq_table[srq].u_handler(label);
else
for (srq = 2; srq < RTAI_NR_SRQS; srq++)
if (test_bit(srq, &rtai_sysreq_map)
&& rtai_sysreq_table[srq].label == label)
r = (long long)srq;
TRACE_RTAI_SRQ_EXIT();
return r;
}
/* this handles the special RTAI syscall (see linux/arch/arm/kernel/entry-common.S)
* that is used to implement LXRT calls and user requests */
static int
rtai_syscall_trampoline(struct pt_regs *regs)
{
unsigned long srq = regs->ARM_r0;
unsigned long arg = regs->ARM_r1;
#ifdef USI_SRQ_MASK
IF_IS_A_USI_SRQ_CALL_IT();
#endif
{
long long r = srq > RTAI_NR_SRQS
? rtai_lxrt_invoke_entry != NULL
? rtai_lxrt_invoke_entry(srq, (void *)arg)
: -ENODEV
: rtai_usrq_trampoline(srq, arg);
*(long long*)&regs->ARM_r0 = r; /* return value of call is expected in saved r0/r1 */
}
if (in_hrt_mode(rtai_cpuid()))
return 1; /* hard real-time => fast return to user-space */
local_irq_enable();
return 0; /* !hard real-time => slow return to user-space */
}
isr_hook_t
rt_set_ihook(isr_hook_t hookfn)
{
#ifdef CONFIG_RTAI_SCHED_ISR_LOCK
return (isr_hook_t)xchg(&rtai_isr_hook, hookfn); /* This is atomic */
#else /* !CONFIG_RTAI_SCHED_ISR_LOCK */
return NULL;
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
void
rtai_set_linux_task_priority(struct task_struct *task, int policy, int prio)
{
task->policy = policy;
task->rt_priority = prio;
set_tsk_need_resched(current);
}
#else
#error "Sorry, Kernels >= 2.6.0 not supported (yet)"
#endif /* KERNEL_VERSION < 2.6.0 */
#ifdef CONFIG_PROC_FS
static int
rtai_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
PROC_PRINT_VARS;
int i, none;
PROC_PRINT("\n** RTAI/ARM %s over Adeos %s\n\n", RTAI_RELEASE, ADEOS_VERSION_STRING);
PROC_PRINT(" TSC frequency: %d Hz\n", RTAI_TSC_FREQ);
PROC_PRINT(" Timer frequency: %d Hz\n", RTAI_TIMER_FREQ);
PROC_PRINT(" Timer latency: %d ns, %d TSC ticks\n", RTAI_TIMER_LATENCY,
rtai_imuldiv(RTAI_TIMER_LATENCY, RTAI_TSC_FREQ, 1000000000));
PROC_PRINT(" Timer setup: %d ns\n", RTAI_TIMER_SETUP_TIME);
PROC_PRINT(" Timer setup: %d TSC ticks, %d IRQ-timer ticks\n",
rtai_imuldiv(RTAI_TIMER_SETUP_TIME, RTAI_TSC_FREQ, 1000000000),
rtai_imuldiv(RTAI_TIMER_SETUP_TIME, RTAI_TIMER_FREQ, 1000000000));
none = 1;
PROC_PRINT("\n** Real-time IRQs used by RTAI: ");
for (i = 0; i < NR_IRQS; i++) {
if (rtai_realtime_irq[i].handler) {
if (none) {
PROC_PRINT("\n");
none = 0;
}
PROC_PRINT("\n #%d at %p", i, rtai_realtime_irq[i].handler);
}
}
if (none)
PROC_PRINT("none");
PROC_PRINT("\n\n");
PROC_PRINT("** RTAI extension traps: \n\n");
PROC_PRINT(" SYSREQ=0x%x\n", RTAI_SYS_VECTOR);
#if 0
PROC_PRINT(" SHM=0x%x\n", RTAI_SHM_VECTOR);
#endif
PROC_PRINT("\n");
none = 1;
PROC_PRINT("** RTAI SYSREQs in use: ");
for (i = 0; i < RTAI_NR_SRQS; i++) {
if (rtai_sysreq_table[i].k_handler || rtai_sysreq_table[i].u_handler) {
PROC_PRINT("#%d ", i);
none = 0;
}
}
if (none)
PROC_PRINT("none");
PROC_PRINT("\n\n");
PROC_PRINT_DONE;
}
static int
rtai_proc_register(void)
{
struct proc_dir_entry *ent;
rtai_proc_root = create_proc_entry("rtai", S_IFDIR, 0);
if (!rtai_proc_root) {
printk(KERN_ERR "RTAI[hal]: Unable to initialize /proc/rtai.\n");
return -1;
}
rtai_proc_root->owner = THIS_MODULE;
ent = create_proc_entry("rtai", S_IFREG|S_IRUGO|S_IWUSR, rtai_proc_root);
if (!ent) {
printk(KERN_ERR "RTAI[hal]: Unable to initialize /proc/rtai/rtai.\n");
return -1;
}
ent->read_proc = rtai_read_proc;
return 0;
}
static void
rtai_proc_unregister(void)
{
remove_proc_entry("rtai", rtai_proc_root);
remove_proc_entry("rtai", 0);
}
#endif /* CONFIG_PROC_FS */
static void
rtai_domain_entry(int iflag)
{
unsigned irq, trapnr;
if (iflag) {
for (irq = 0; irq < NR_IRQS; irq++)
adeos_virtualize_irq(irq,
&rtai_irq_trampoline,
NULL,
IPIPE_DYNAMIC_MASK);
/* Trap all faults. (Adeos for ARM doesn't generate any traps at all!) */
for (trapnr = 0; trapnr < ADEOS_NR_FAULTS; trapnr++)
adeos_catch_event(trapnr, &rtai_trap_fault);
printk(KERN_INFO "RTAI[hal]: %s mounted over Adeos %s.\n", PACKAGE_VERSION, ADEOS_VERSION_STRING);
printk(KERN_INFO "RTAI[hal]: compiled with %s.\n", CONFIG_RTAI_COMPILER);
}
#ifdef CONFIG_ADEOS_THREADS
for (;;)
adeos_suspend_domain();
#endif /* CONFIG_ADEOS_THREADS */
}
int
__rtai_hal_init(void)
{
unsigned long flags;
adattr_t attr;
/* Allocate a virtual interrupt to handle sysreqs within the Linux
domain. */
rtai_sysreq_virq = adeos_alloc_irq();
if (!rtai_sysreq_virq) {
printk(KERN_ERR "RTAI[hal]: no virtual interrupt available.\n");
return 1;
}
/* Reserve the first two _consecutive_ per-thread data key in the
Linux domain. This is rather crappy, since we depend on
statically defined PTD key values, which is exactly what the
PTD scheme is here to prevent. Unfortunately, reserving these
specific keys is the only way to remain source compatible with
the current LXRT implementation. */
flags = rtai_critical_enter(NULL);
rtai_adeos_ptdbase = adeos_alloc_ptdkey();
if (adeos_alloc_ptdkey() != rtai_adeos_ptdbase + 1) {
rtai_critical_exit(flags);
printk(KERN_ERR "RTAI[hal]: per-thread keys not available.\n");
return 1;
}
/* install RTAI syscall handler */
rtai_lxrt_invoke_entry = NULL;
saved_adeos_syscall_handler = xchg(&adeos_syscall_entry, rtai_syscall_trampoline);
rtai_critical_exit(flags);
adeos_virtualize_irq(rtai_sysreq_virq,
&rtai_ssrq_trampoline,
NULL,
IPIPE_HANDLE_MASK);
/* set TSC frequency, other values of rtai_tunables are set by the scheduler */
rtai_tunables.cpu_freq = RTAI_TSC_FREQ;
#ifdef CONFIG_PROC_FS
rtai_proc_register();
#endif
/* do (sub-)architecture specific initializations */
rtai_archdep_init();
/* Let Adeos do its magic for our piped irq dispatching real-time domain. */
adeos_init_attr(&attr);
attr.name = "RTAI";
attr.domid = RTAI_DOMAIN_ID;
attr.entry = &rtai_domain_entry;
attr.priority = ADEOS_ROOT_PRI + 100; /* Precede Linux in the pipeline */
printk(KERN_INFO "RTAI[hal]: mounted (PIPED).\n");
return adeos_register_domain(&rtai_domain, &attr);
}
void
__rtai_hal_exit(void)
{
unsigned long flags;
/* do (sub-)architecture specific cleanup */
rtai_archdep_exit();
#ifdef CONFIG_PROC_FS
rtai_proc_unregister();
#endif
adeos_virtualize_irq(rtai_sysreq_virq, NULL, NULL, 0);
adeos_free_irq(rtai_sysreq_virq);
/* deinstall RTAI syscall handler */
flags = rtai_critical_enter(NULL);
adeos_syscall_entry = saved_adeos_syscall_handler;
rtai_lxrt_invoke_entry = NULL;
rtai_critical_exit(flags);
adeos_free_ptdkey(rtai_adeos_ptdbase); /* #0 and #1 actually */
adeos_free_ptdkey(rtai_adeos_ptdbase + 1);
adeos_unregister_domain(&rtai_domain);
printk(KERN_INFO "RTAI[hal]: unmounted.\n");
}
module_init(__rtai_hal_init);
module_exit(__rtai_hal_exit);
EXPORT_SYMBOL(rt_request_irq);
EXPORT_SYMBOL(rt_release_irq);
EXPORT_SYMBOL(rt_set_irq_cookie);
EXPORT_SYMBOL(rt_startup_irq);
EXPORT_SYMBOL(rt_shutdown_irq);
EXPORT_SYMBOL(rt_enable_irq);
EXPORT_SYMBOL(rt_disable_irq);
EXPORT_SYMBOL(rt_mask_and_ack_irq);
EXPORT_SYMBOL(rt_unmask_irq);
EXPORT_SYMBOL(rt_ack_irq);
EXPORT_SYMBOL(rt_request_linux_irq);
EXPORT_SYMBOL(rt_free_linux_irq);
EXPORT_SYMBOL(rt_pend_linux_irq);
EXPORT_SYMBOL(rt_request_srq);
EXPORT_SYMBOL(rt_free_srq);
EXPORT_SYMBOL(rt_pend_linux_srq);
EXPORT_SYMBOL(rt_request_timer);
EXPORT_SYMBOL(rt_free_timer);
EXPORT_SYMBOL(rt_set_trap_handler);
EXPORT_SYMBOL(rt_set_ihook);
EXPORT_SYMBOL(rtai_critical_enter);
EXPORT_SYMBOL(rtai_critical_exit);
EXPORT_SYMBOL(rtai_set_linux_task_priority);
EXPORT_SYMBOL(rtai_linux_context);
EXPORT_SYMBOL(rtai_domain);
EXPORT_SYMBOL(rtai_proc_root);
EXPORT_SYMBOL(rtai_tunables);
EXPORT_SYMBOL(rtai_cpu_lock);
EXPORT_SYMBOL(rtai_cpu_realtime);
EXPORT_SYMBOL(rt_times);
EXPORT_SYMBOL(rt_smp_times);
EXPORT_SYMBOL(rtai_lxrt_invoke_entry);
EXPORT_SYMBOL(rtai_realtime_irq);
EXPORT_SYMBOL(rt_scheduling);

View file

@ -0,0 +1,127 @@
/* rtai/arch/arm/mach-at91/at91-timer.c
COPYRIGHT (C) 2002 Guennadi Liakhovetski, DSA GmbH (gl@dsa-ac.de)
COPYRIGHT (C) 2002 Wolfgang Müller (wolfgang.mueller@dsa-ac.de)
Copyright (c) 2001 Alex Züpke, SYSGO RTS GmbH (azu@sysgo.de)
Copyright (c) 2005 Luca Pizzi, (lucapizzi@hotmail.com)
Copyright (c) 2005 Stefano Gafforelli, (stefano.gafforelli@tiscali.it)
Copyright (C) 2007 Adeneo
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
*/
/*
--------------------------------------------------------------------------
Acknowledgements
- Paolo Mantegazza (mantegazza@aero.polimi.it)
creator of RTAI
*/
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/mach/irq.h>
#include <asm/system.h>
#include <rtai.h>
#include <asm/arch/timex.h>
#include <asm/arch/rtai_timer.h>
#include <rtai_trace.h>
#include <asm/arch/rtai_timer.h>
extern int (*extern_timer_isr)(struct pt_regs *regs);
extern int rtai_timer_handler(struct pt_regs *regs);
unsigned int rt_periodic;
EXPORT_SYMBOL(rt_periodic);
int rt_request_timer (void (*handler)(void), unsigned tick, int use_apic)
{
unsigned long flags;
flags = rtai_critical_enter(NULL);
__ipipe_mach_timerstolen = 1; // no need to reprogram timer on timer_tick() call
rt_times.tick_time = rtai_rdtsc();
rt_times.linux_tick = __ipipe_mach_ticks_per_jiffy;
if (tick > 0) {
rt_periodic = 1;
/* Periodic setup --
Use the built-in Adeos service directly. */
if (tick > __ipipe_mach_ticks_per_jiffy) {
tick = __ipipe_mach_ticks_per_jiffy;
}
rt_times.intr_time = rt_times.tick_time + tick;
rt_times.linux_time = rt_times.tick_time + rt_times.linux_tick;
rt_times.periodic_tick = tick;
/* Prepare TCx to reload automaticly on RC compare */
at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3 | AT91_TC_WAVESEL_UP_AUTO | AT91_TC_WAVE);
at91_tc_write(AT91_TC_RC, rt_times.periodic_tick);
at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
} else {
rt_periodic = 0;
/* Oneshot setup. */
rt_times.intr_time = rt_times.tick_time + rt_times.linux_tick;
rt_times.linux_time = rt_times.tick_time + rt_times.linux_tick;
rt_times.periodic_tick = rt_times.linux_tick;
/* Prepare TCx behaviour as oneshot timer */
at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
rt_set_timer_delay(rt_times.periodic_tick);
}
rt_release_irq(RTAI_TIMER_IRQ);
rt_request_irq(RTAI_TIMER_IRQ, (rt_irq_handler_t)handler, NULL, 0);
extern_timer_isr = rtai_timer_handler; // shunt for ipipe.c __ipipe_grab_irq
rtai_critical_exit(flags);
return 0;
}
void rt_free_timer (void)
{
unsigned long flags;
rt_periodic = 0;
__ipipe_mach_timerstolen = 0; // ipipe can reprogram timer for Linux now
at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3); // back to oneshot mode
rt_set_timer_delay(__ipipe_mach_ticks_per_jiffy); // regular timer delay
rt_release_irq(RTAI_TIMER_IRQ); // free this irq
rtai_save_flags_and_cli(flags); // critical section
extern_timer_isr = NULL; // let ipipe run as normally
rtai_restore_flags(flags); // end of critical section
}
int rtai_calibrate_TC (void)
{
unsigned long flags;
RTIME t, dt;
int i;
flags = rtai_critical_enter(NULL);
rt_set_timer_delay(LATCH);
t = rtai_rdtsc();
for (i = 0; i < 10000; i++) {
rt_set_timer_delay(LATCH);
}
dt = rtai_rdtsc() - t;
rtai_critical_exit(flags);
return rtai_imuldiv(dt, 100000, RTAI_CPU_FREQ);
}

View file

@ -0,0 +1,144 @@
/*
* ARM/EP9301 specific timer code
*
* COPYRIGHT (C) 2004 Michael Neuhauser, Firmix Software GmbH <mike@firmix.at>
*
* Acknowledgements:
* Paolo Mantegazza <mantegazza@aero.polimi.it>, creator of RTAI
*
* 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 <rtai_trace.h>
#include <asm/arch/ep93xx_tsc.h>
/*
* Install a timer interrupt handler as a real-time ISR and set hardware-timer
* to requested period.
* tick = 0: oneshot mode
* tick > 0: periodic mode (and tick specifies the period in timer-ticks)
*/
int
rt_request_timer(rt_timer_irq_handler_t handler, unsigned int tick, int i386_legacy_dummy)
{
unsigned long flags;
int is_oneshot = (tick == 0);
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_REQUEST, handler, tick);
/* initial one-shot delay is 1/HZ seconds */
if (is_oneshot)
tick = LATCH;
flags = rtai_critical_enter(NULL);
/* stop timer & set reload value */
outl(0, TIMER1CONTROL);
outl(tick - 1, TIMER1LOAD);
/* sync to jiffy clock phase (still neccessary with Adeos?) */
rt_times.tick_time = ({
ep93xx_tsc_t t0;
unsigned long target_offset;
unsigned long t;
/* spin until we are not to close (~ 10 µs) before jiffy time-point */
do {
t0.ll = ep93xx_rdtsc();
unsigned long long const realtime_jiffies = (long long)(t0.ll * HZ) / (long)RTAI_TSC_FREQ;
unsigned long const current_offset = t0.ll - (realtime_jiffies * RTAI_TSC_FREQ) / HZ;
target_offset = ((RTAI_TSC_FREQ + HZ/2) / HZ) - current_offset;
} while (target_offset < 10);
/* spin until we have passed jiffy time-point */
do {
t = inl(TIMER4VALUELOW);
} while ((t - t0.u.low) < target_offset);
/* quickly start timer (508.469 kHz clock, free runing or periodic mode) */
outl((is_oneshot) ? 0x88 : 0xc8, TIMER1CONTROL);
/* set t0 to current time */
if (t < t0.u.low)
++t0.u.high;
t0.u.low = t;
t0.ll;
});
/* ack interrupt (timer may have underflowed since lock) */
outl(1, TIMER1CLEAR);
/* set up rt_times structure */
if (is_oneshot) {
/* oneshot mode: unit is TSC-tick */
rt_times.linux_time = rtai_llimd(ep93xx_jiffies_done * LATCH, RTAI_TSC_FREQ, RTAI_TIMER_FREQ);
rt_times.linux_tick = rtai_imuldiv(LATCH, RTAI_TSC_FREQ, RTAI_TIMER_FREQ);
rt_times.periodic_tick = rt_times.linux_tick;
} else {
/* periodic mode: unit is irq-timer-tick */
rt_times.tick_time = rtai_llimd(rt_times.tick_time, RTAI_TIMER_FREQ, RTAI_TSC_FREQ);
rt_times.linux_time = ep93xx_jiffies_done * LATCH;
rt_times.linux_tick = LATCH;
rt_times.periodic_tick = tick;
}
rt_times.intr_time = rt_times.tick_time + rt_times.periodic_tick;
rt_release_irq(RTAI_TIMER_IRQ);
if (rt_request_irq(RTAI_TIMER_IRQ, (rt_irq_handler_t)handler, NULL, 0) < 0) {
rtai_critical_exit(flags);
return -EINVAL;
}
/* Note that it is not necessary to change the linux handler of the
* timer-irq as it was done on RTAI/ARM before Adeos. This was done to
* enable/disable hardware ack. Now Adeos will do all for us, using the
* irq_des[].mask_ack function (which has to be set up accordingly in
* arch/arm/mach-MACH/irq.c:MACH_init_irq()).
*/
rtai_critical_exit(flags);
return 0;
}
/*
* Uninstall a timer handler previously set by rt_request_timer() and reset
* hardware-timer to Linux HZ-tick.
*/
void
rt_free_timer(void)
{
unsigned long flags;
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_FREE, 0, 0);
flags = rtai_critical_enter(NULL);
/* no need to sync with linux jiffy clock because jiffy clock is synced to
* TSC (i.e. absolute time) by linux timer interrupt handlers */
/* stop timer for re-programming */
outl(0, TIMER1CONTROL);
/* set reload value */
outl(LATCH - 1, TIMER1LOAD);
/* set timer to 508 kHz clock, periodic mode and start it */
outl(0xc8, TIMER1CONTROL);
/* ack interrupt that may have occured */
outl(1, TIMER1CLEAR);
rt_release_irq(RTAI_TIMER_IRQ);
rtai_critical_exit(flags);
}

View file

@ -0,0 +1,123 @@
/* rtai/arch/arm/mach-imx/imx-timer.c
COPYRIGHT (C) 2002 Guennadi Liakhovetski, DSA GmbH (gl@dsa-ac.de)
COPYRIGHT (C) 2002 Wolfgang Müller (wolfgang.mueller@dsa-ac.de)
Copyright (c) 2001 Alex Züpke, SYSGO RTS GmbH (azu@sysgo.de)
Copyright (c) 2005 Luca Pizzi, (lucapizzi@hotmail.com)
Copyright (c) 2005 Stefano Gafforelli, (stefano.gafforelli@tiscali.it)
Copyright (c) 2006 Torsten Koschorrek, (koschorrek@synertronixx.de)
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
*/
/*
--------------------------------------------------------------------------
Acknowledgements
- Paolo Mantegazza (mantegazza@aero.polimi.it)
creator of RTAI
- port to imx architecture using both pxa-timer.c and ep9301-timer.c
20060613: Torsten Koschorrek (koschorrek@synertronixx.de)
*/
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/mach/irq.h>
#include <asm/system.h>
#include <rtai.h>
#include <asm-arm/arch-imx/timex.h>
#include <asm-arm/arch-imx/rtai_timer.h>
#include <rtai_trace.h>
volatile union rtai_tsc rtai_tsc;
EXPORT_SYMBOL(rtai_tsc);
static int (*saved_adeos_timer_handler)(int irq, void *dev_id, struct pt_regs *regs);
volatile union rtai_tsc lx_timer;
unsigned long split_timer (void) {
lx_timer.tsc = rt_times.linux_time;
return lx_timer.hltsc[0];
}
int soft_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
long flags;
rdtsc(); /* update tsc - make sure we don't miss a wrap */
local_irq_save(flags);
do_timer(regs);
split_timer();
local_irq_restore(flags);
return IRQ_HANDLED;
}
int rt_request_timer(rt_timer_irq_handler_t handler, unsigned tick, int use_apic)
{
RTIME t;
unsigned long flags;
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_REQUEST, handler, tick);
flags = rtai_critical_enter(NULL);
/* sync w/jiffie, wait for a timer match 0 and clear the match bit */
rtai_tsc.tsc = 0;
do {} while ((signed long)(IMX_TCMP(0) - IMX_TCN(0)) > 0);
/* set up rt_times structure */
rt_times.linux_tick = LATCH;
rt_times.periodic_tick = (tick > 0 && tick < (RTIME)rt_times.linux_tick) ? tick : rt_times.linux_tick;
rt_times.tick_time = t = rdtsc();
rt_times.intr_time = t + rt_times.periodic_tick;
rt_times.linux_time = t + rt_times.linux_tick;
/* Trick the scheduler - set this our way. */
// tuned.setup_time_TIMER_CPUNIT = (int)(~(~0 >> 1)) + 1; /* smallest negative + 1 - for extra safety:-) */
/* update Match-register */
rt_set_timer_delay(rt_times.periodic_tick);
saved_adeos_timer_handler = xchg(&irq_desc[TIMER_8254_IRQ].action->handler, (void *)soft_timer_interrupt);
rt_free_global_irq(TIMER_8254_IRQ);
rt_request_global_irq(TIMER_8254_IRQ, handler);
/* pend linux timer irq to handle current jiffie */
rt_pend_linux_irq(TIMER_8254_IRQ);
rtai_critical_exit(flags);
return 0;
}
void rt_free_timer(void)
{
unsigned long flags;
if(saved_adeos_timer_handler == NULL)
return;
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_FREE, 0, 0);
flags = rtai_critical_enter(NULL);
rt_free_global_irq(TIMER_8254_IRQ);
irq_desc[TIMER_8254_IRQ].action->handler =(void*)saved_adeos_timer_handler ;
rtai_critical_exit(flags);
}

View file

@ -0,0 +1,139 @@
/* rtai/arch/arm/mach-pxa/pxa-timer.c
COPYRIGHT (C) 2002 Guennadi Liakhovetski, DSA GmbH (gl@dsa-ac.de)
COPYRIGHT (C) 2002 Wolfgang Müller (wolfgang.mueller@dsa-ac.de)
Copyright (c) 2001 Alex Züpke, SYSGO RTS GmbH (azu@sysgo.de)
Copyright (c) 2005 Luca Pizzi, (lucapizzi@hotmail.com)
Copyright (c) 2005 Stefano Gafforelli, (stefano.gafforelli@tiscali.it)
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
*/
/*
--------------------------------------------------------------------------
Acknowledgements
- Paolo Mantegazza (mantegazza@aero.polimi.it)
creator of RTAI
*/
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/mach/irq.h>
#include <asm/system.h>
#include <rtai.h>
#define do_leds()
#define do_set_rtc()
#define do_profile(x)
extern struct irqaction timer_irq;
extern unsigned long (*gettimeoffset)(void);
extern int (*set_rtc)(void);
#include <asm-arm/arch-pxa/timex.h>
#include <asm-arm/arch-pxa/rtai_timer.h>
#include <rtai_trace.h>
volatile union rtai_tsc rtai_tsc;
EXPORT_SYMBOL(rtai_tsc);
extern volatile u32 soft_timer_match;
extern void timer_tick(struct pt_regs *);
static int (*saved_adeos_timer_handler)(int irq, void *dev_id, struct pt_regs *regs);
void rtai_pxa_GPIO_2_80_demux( int irq, void *dev_id, struct pt_regs *regs )
{
/* No pending to linux! */
}
volatile union rtai_tsc lx_timer;
unsigned long split_timer (void) {
lx_timer.tsc = rt_times.linux_time;
return lx_timer.hltsc[0];
}
int soft_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
long flags;
rdtsc(); /* update tsc - make sure we don't miss a wrap */
local_irq_save(flags);
timer_tick(regs);
soft_timer_match = split_timer();
local_irq_restore(flags);
return IRQ_HANDLED;
}
int rt_request_timer(rt_timer_irq_handler_t handler, unsigned tick, int use_apic)
{
RTIME t;
unsigned long flags;
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_REQUEST, handler, tick);
flags = rtai_critical_enter(NULL);
/*
* sync w/jiffie, wait for a OS timer 0 match and clear the match bit
*/
rtai_tsc.tsc = 0;
/* wait for a timer match 0 and clear the match bit */
do {
// t = rdtsc();
} while ( (signed long)(OSMR0 - OSCR) >= 0 );
OSSR = OSSR_M0;
/* set up rt_times structure */
rt_times.linux_tick = LATCH;
rt_times.periodic_tick = tick > 0 && tick < (RTIME)rt_times.linux_tick ? tick : rt_times.linux_tick;
rt_times.tick_time = t = rdtsc();
rt_times.intr_time = t + (RTIME)rt_times.periodic_tick;
rt_times.linux_time = t + (RTIME)rt_times.linux_tick;
/* Trick the scheduler - set this our way. */
// tuned.setup_time_TIMER_CPUNIT = (int)(~(~0 >> 1)) + 1; /* smallest negative + 1 - for extra safety:-) */
/* update Match-register */
rt_set_timer_match_reg(rt_times.periodic_tick);
saved_adeos_timer_handler = xchg(&irq_desc[TIMER_8254_IRQ].action->handler,(void *)soft_timer_interrupt);
rt_free_global_irq(TIMER_8254_IRQ);
rt_request_global_irq(TIMER_8254_IRQ, handler);
/*
* pend linux timer irq to handle current jiffie
*/
rt_pend_linux_irq(TIMER_8254_IRQ);
rtai_critical_exit(flags);
return 0;
}
void rt_free_timer(void)
{
unsigned long flags;
TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_FREE, 0, 0);
flags = rtai_critical_enter(NULL);
rt_free_global_irq(TIMER_8254_IRQ);
irq_desc[TIMER_8254_IRQ].action->handler =(void*)saved_adeos_timer_handler ;
rtai_critical_exit(flags);
}

View file

@ -0,0 +1,160 @@
ep9301_hal17_2.4.21-rmk1-crus1.4.2
==================================
2005-02-22 Michael Neuhauser <mike@firmix.at>
Supports Cirrus EDB9301 development board with EP9301 CPU (ARM920T)
-> http://www.cirrus.com/en/products/EDB9301_offer.html
Might also work (with a little tweaking) with TS-7200 board from
Technologic Systems
-> http://www.embeddedarm.com/epc/ts7200-spec-h.html
needs gcc >= 3.1 (3.3.2 was used during development)
Patch chain:
* base is vanilla Linux 2.4.21
-> http://kernel.org/pub/linux/kernel/v2.4/linux-2.4.21.tar.bz2
* apply Russel M. King's patch for this kernel:
patch-2.4.21-rmk1
-> http://www.arm.linux.org.uk/developer/v2.4/
* apply non-public patch from board manufacturer:
linux-2.4.21-rmk1-crus1.4.2.patch
-> get it from your friendly neighborhood RTAI/ARM
maintainer (Michael Neuhauser <mike@firmix.at>)
* apply Adeos patch:
ep9301_hal17_2.4.21-rmk1-crus1.4.2.patch
-> from here
file history:
2005-01-31 added to magma
pxa255_2.6.7-bk6-karo
=====================
2005-02-22 Michael Neuhauser <mike@firmix.at>
Supports Triton LP board with PXA255 CPU
-> http://www.karo-electronics.de/index.php?id=15&L=1
**********************************************
*** Only immediate mode RTAI is supported! ***
**********************************************
(See ../../../../README.INSTALL for an explanation of immediate/piped mode.
Bottom line: you have to execute "./mode-control immed" in ../../../scripts)
Patch chain:
* base is vanilla Linux 2.6.7
-> http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.7.tar.bz2
* apply "official" kernel snapshot patch:
patch-2.6.7-bk6
-> http://www.kernel.org/pub/linux/kernel/v2.6/snapshots/old/patch-2.6.7-bk6.bz2
* apply non-public(?) patch by board manufacturer:
linux-2.6.7-bk6-karo.patch
-> get it from your friendly neighborhood RTAI/ARM
maintainer (Michael Neuhauser <mike@firmix.at>)
* apply Adeos patch:
pxa255_2.6.7-bk6-karo.patch
-> from here
file history:
2005-02-22 added to magma
at91_2.6.20.13
==============
2007-09-14 Adeneo (by Gregory Clement, Alexandre Bouin)
A patch to support the related Linux version on ARM-AT91, to be used after
patching magma with: RTAI-magma-AT91.patch, also found in this repository.
patch chain:
linux-2.6.20.13-vanilla
adeos-ipipe-2.6.20-arm-1.7-03.patch (from adeos project / http://gna.org/projects/adeos/)
at91_2.6.20.13.patch
file history:
2007-09-14 added to www.rtai.org/RTAICONTRIB
2008-08-06 renamed (hal-linux-2.6.20-arm-AT91 -> at91_hal-linux-2.6.20-arm-AT91)
2008-08-06 added to magma
2010-03-04 renamed (at91_hal-linux-2.6.20-arm-AT91 -> at91_2.6.20.13)
at91_2.6.20.13-at91sam9263
==========================
2008-04-04 Adeneo (by Gregory CLEMENT and Alexandre BOUIN)
The base patch to support RTAI-magma-AT91 and RTAI-3.5-cv-AT91.
This kernel patch adds additional rtai support for at91sam9263.
patch chain:
linux-2.6.20.13-vanilla
adeos-ipipe-2.6.20-arm-1.7-03.patch (from adeos project / http://gna.org/projects/adeos/)
at91_2.6.20.13.patch
<kernel support for at91sam9263>
at91_2.6.20.13-at91sam9263.patch
file history:
2008-04-04 added to www.rtai.org/RTAICONTRIB
2008-08-06 renamed (adeos-ipipe-2.6.20-arm-AT91 -> at91_adeos-ipipe-2.6.20-arm-AT91)
2008-08-06 added to magma
2010-03-04 renamed (at91_adeos-ipipe-2.6.20-arm-AT91 -> at91_2.6.20.13-at91sam9263)
imxl_2.6.7
==========
2008-08-06 Torsten Koschorrek <devel@koschorrek.com>
Linux Kernel patch for mach-imx (iMXL).
patch chain:
linux-2.6.7-vanilla
<kernel support for iMXL>
imxl_2.6.7.patch
file history:
2008-08-06 added to magma
2010-03-04 renamed (imx_2.6.7_rtai_3.2_v_1.0 -> imxl_2.6.7)
-----
RTAI-magma-AT91 (DEPRECATED)
============================
2007-09-14 Adeneo (by Gregory Clement, Alexandre Bouin)
A patch to apply to the RTAI development CVS "MAGMA" to extend its support
to ARM-AT91; it is a working release that is known to have pretty low real
time latencies now. Notice that since "MAGMA" might have changed you should
care of checking it out with the date of the content of this patch, or use
the following item otherwise.
file history:
2007-09-14 added to www.rtai.org/RTAICONTRIB
2008-08-06 added to magma
2010-07-08 this patch is included in rtai and deprecated!
RTAI-3.5-cv-AT91-v2 (DEPRECATED)
================================
2007-09-14 Adeneo (by Gregory Clement, Alexandre Bouin)
A patch to apply to RTAI-3.5-cv release to extend it to support ARM-AT91.
The same as above but for 3.5-cv version.
file history:
2007-09-14 added to www.rtai.org/RTAICONTRIB
2008-08-06 added to magma
2010-07-08 this patch is included in rtai and deprecated!
RTAI-3.2-IMX (DEPRECATED)
=========================
2008-08-06 Torsten Koschorrek <devel@koschorrek.com>
Patch for rtai, as long as there is no support in official latest releases
file history:
2008-08-06 added to magma
2010-07-08 this patch is included in rtai and deprecated!

View file

@ -0,0 +1,181 @@
diff -aurdpbB -X nodiff linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/at91sam9263.c linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/at91sam9263.c
--- linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/at91sam9263.c 2007-06-19 14:32:37.000000000 +0200
+++ linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/at91sam9263.c 2007-06-19 17:53:14.000000000 +0200
@@ -28,6 +28,13 @@ static struct map_desc at91sam9263_io_de
.length = SZ_16K,
.type = MT_DEVICE,
}, {
+#ifdef CONFIG_IPIPE
+ .virtual = AT91_VA_BASE_TCB0,
+ .pfn = __phys_to_pfn(AT91SAM9263_BASE_TCB0),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+#endif /* CONFIG_IPIPE */
.virtual = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE,
.pfn = __phys_to_pfn(AT91SAM9263_SRAM0_BASE),
.length = AT91SAM9263_SRAM0_SIZE,
@@ -266,6 +273,7 @@ void __init at91sam9263_initialize(unsig
* The default interrupt priority levels (0 = lowest, 7 = highest).
*/
static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
7, /* Advanced Interrupt Controller (FIQ) */
7, /* System Peripherals */
0, /* Parallel IO Controller A */
@@ -298,6 +306,42 @@ static unsigned int at91sam9263_default_
3, /* USB Host port */
0, /* Advanced Interrupt Controller (IRQ0) */
0, /* Advanced Interrupt Controller (IRQ1) */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+ I-pipe. */
+ 7, /* Advanced Interrupt Controller (FIQ) */
+ 7, /* System Peripherals */
+ 0, /* Parallel IO Controller A */
+ 0, /* Parallel IO Controller B */
+ 0, /* Parallel IO Controller C, D and E */
+ 0,
+ 0,
+ 6, /* USART 0 */
+ 6, /* USART 1 */
+ 6, /* USART 2 */
+ 0, /* Multimedia Card Interface 0 */
+ 0, /* Multimedia Card Interface 1 */
+ 4, /* CAN */
+ 0, /* Two-Wire Interface */
+ 6, /* Serial Peripheral Interface 0 */
+ 6, /* Serial Peripheral Interface 1 */
+ 5, /* Serial Synchronous Controller 0 */
+ 5, /* Serial Synchronous Controller 1 */
+ 6, /* AC97 Controller */
+ 7, /* Timer Counter 0, 1 and 2 */
+ 0, /* Pulse Width Modulation Controller */
+ 3, /* Ethernet */
+ 0,
+ 0, /* 2D Graphic Engine */
+ 3, /* USB Device Port */
+ 0, /* Image Sensor Interface */
+ 3, /* LDC Controller */
+ 0, /* DMA Controller */
+ 0,
+ 3, /* USB Host port */
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ 0, /* Advanced Interrupt Controller (IRQ1) */
+#endif /*CONFIG_IPIPE */
};
void __init at91sam9263_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -aurdpbB -X nodiff linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/at91sam926x_time.c 2007-06-18 14:17:18.000000000 +0200
+++ linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/at91sam926x_time.c 2007-06-21 11:46:11.000000000 +0200
@@ -46,6 +46,11 @@ static unsigned long last_crtr;
#define AT91_ID_TC0 AT91SAM9261_ID_TC0
#define AT91_ID_TC1 AT91SAM9261_ID_TC1
#define AT91_ID_TC2 AT91SAM9261_ID_TC2
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+#include <asm/arch/at91sam9263.h>
+#define AT91_ID_TC0 AT91SAM9263_ID_TCB
+#define AT91_ID_TC1 AT91SAM9263_ID_TCB
+#define AT91_ID_TC2 AT91SAM9263_ID_TCB
#else
#error "Unsupported AT91 processor"
#endif
@@ -107,6 +112,7 @@ static int at91_timer_initialized;
* Returns number of microseconds since last timer interrupt. Note that interrupts
* will have been disabled by do_gettimeofday()
* 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+ * 'tick' is usecs per jiffy (linux/timex.h).
*/
static unsigned long at91sam926x_gettimeoffset(void)
{
@@ -115,7 +121,7 @@ static unsigned long at91sam926x_gettime
elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */
- return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH;
+ return (unsigned long)(elapsed * 1000000) / LATCH;
}
/*
@@ -357,14 +363,9 @@ static struct irqaction at91sam926x_time
.handler = &at91sam926x_timer_interrupt
};
-static char clk_name [] = "tc%";
+static char clk_name [] = "tc%_clk";
-static struct clk tc = {
- .name = (const char *) clk_name,
- .users = 0,
- .type = CLK_TYPE_PERIPHERAL,
- .pmc_mask = 1 << (KERNEL_TIMER_IRQ_NUM),
-};
+static struct clk *tc;
void __init at91sam926x_timer_init(void)
{
@@ -373,9 +374,19 @@ void __init at91sam926x_timer_init(void)
if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
- snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
- clk_register(&tc);
- clk_enable(&tc);
+ /* since 2.6.20-at91.patch, all clocks are registered on startup.
+ * we just need to get the good struct and enable our tc clock */
+#ifdef CONFIG_ARCH_AT91SAM9263
+ snprintf(clk_name, sizeof(clk_name), "tcb_clk");
+#else
+ snprintf(clk_name, sizeof(clk_name), "tc%d_clk", CONFIG_IPIPE_AT91_TC);
+#endif /* CONFIG_ARCH_AT91SAM9263 */
+
+ tc = clk_get(NULL, clk_name);
+ if((int)tc == 0xfffffffe) //err code
+ printk("> %s does not exist.",clk_name);
+ else
+ clk_enable(tc);
/* No Sync. */
at91_tc_write(AT91_TC_BCR, 0);
diff -aurdpbB -X nodiff linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/Kconfig linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/Kconfig
--- linux-2.6.20.13-9263-clean/arch/arm/mach-at91rm9200/Kconfig 2007-06-18 14:17:18.000000000 +0200
+++ linux-2.6.20.13-9263/arch/arm/mach-at91rm9200/Kconfig 2007-06-19 17:57:34.000000000 +0200
@@ -153,6 +153,7 @@ config IPIPE_AT91_MCK
default 46080000 if MACH_CSB637
default 59904000 if MACH_AT91RM9200EK
default 99328000 if MACH_AT91SAM9260EK || MACH_AT91SAM9261EK
+ default 99959589 if MACH_AT91SAM9263EK
default 53000000
help
When Adeos interrupt pipeline is enabled, AT91 timer is based on
diff -aurdpbB -X nodiff linux-2.6.20.13-9263-clean/include/asm-arm/arch-at91rm9200/hardware.h linux-2.6.20.13-9263/include/asm-arm/arch-at91rm9200/hardware.h
--- linux-2.6.20.13-9263-clean/include/asm-arm/arch-at91rm9200/hardware.h 2007-06-18 14:17:18.000000000 +0200
+++ linux-2.6.20.13-9263/include/asm-arm/arch-at91rm9200/hardware.h 2007-06-19 16:25:48.000000000 +0200
@@ -53,7 +53,9 @@
#define AT91_BASE_TCB0 AT91SAM9260_BASE_TCB0
#elif defined(CONFIG_ARCH_AT91SAM9261)
#define AT91_BASE_TCB0 AT91SAM9261_BASE_TCB0
-#endif /* CONFIG_ARCH_AT91SAM9261 */
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+#define AT91_BASE_TCB0 AT91SAM9263_BASE_TCB0
+#endif /* CONFIG_ARCH_AT91 */
#define AT91_VA_BASE_TCB0 AT91_IO_P2V(AT91_BASE_TCB0)
#endif /* CONFIG_IPIPE */
diff -aurdpbB -X nodiff linux-2.6.20.13-9263-clean/include/asm-arm/arch-at91rm9200/irqs.h linux-2.6.20.13-9263/include/asm-arm/arch-at91rm9200/irqs.h
--- linux-2.6.20.13-9263-clean/include/asm-arm/arch-at91rm9200/irqs.h 2007-06-18 14:17:18.000000000 +0200
+++ linux-2.6.20.13-9263/include/asm-arm/arch-at91rm9200/irqs.h 2007-06-18 14:35:54.000000000 +0200
@@ -55,7 +55,11 @@ extern unsigned __ipipe_at91_gpio_banks;
#elif defined(CONFIG_ARCH_AT91SAM9261)
#define __ipipe_mach_irq_mux_p(irq) \
((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
-#endif /* CONFIG_ARCH_AT91SAM9261 */
+
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+#define __ipipe_mach_irq_mux_p(irq) \
+ ((unsigned) (irq - AT91SAM9263_ID_PIOA) < __ipipe_at91_gpio_banks)
+#endif /* CONFIG_ARCH_AT91 */
#endif /* CONFIG_IPIPE && !__ASSEMBLY__ */

View file

@ -0,0 +1,424 @@
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/arch/arm/kernel/ipipe.c linux-2.6.20.13/arch/arm/kernel/ipipe.c
--- linux-2.6.20.13-clean/arch/arm/kernel/ipipe.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/arch/arm/kernel/ipipe.c 2007-08-23 13:44:07.000000000 +0200
@@ -192,6 +192,21 @@ void __ipipe_enable_irqdesc(unsigned irq
irq_desc[irq].status &= ~IRQ_DISABLED;
}
+/*
+ * In Linux setup_irq, status is used to manage nested IRQ
+ */
+void __ipipe_enable_depth(unsigned irq)
+{
+ if(!(irq_desc[irq].status & IRQ_NOAUTOEN))
+ irq_desc[irq].depth = 1;
+}
+
+void __ipipe_disable_depth(unsigned irq)
+{
+ if(!(irq_desc[irq].status & IRQ_NOAUTOEN))
+ irq_desc[irq].depth = 0;
+}
+
static void __ipipe_enable_sync(void)
{
__ipipe_decr_next[ipipe_processor_id()] =
@@ -353,9 +368,9 @@ asmlinkage int __ipipe_syscall_root(unsi
* tail work has to be performed (for handling signals etc).
*/
- if (__ipipe_syscall_watched_p(current, regs->ARM_r7) &&
+ if (__ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0 &&
__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
- __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) {
+ __ipipe_syscall_watched_p(current, regs->ARM_r7)) {
if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) {
/*
* Sync pending VIRQs before _TIF_NEED_RESCHED
@@ -469,6 +484,11 @@ finalize:
__ipipe_walk_pipeline(head, cpuid);
}
+int (*extern_timer_isr)(struct pt_regs *regs);
+EXPORT_SYMBOL(extern_timer_isr);
+
+#include <asm/arch/at91_pio.h>
+
asmlinkage int __ipipe_grab_irq(int irq, struct pt_regs *regs)
{
ipipe_declare_cpuid;
@@ -478,6 +498,8 @@ asmlinkage int __ipipe_grab_irq(int irq,
__ipipe_tick_regs[cpuid].ARM_cpsr = regs->ARM_cpsr;
__ipipe_tick_regs[cpuid].ARM_pc = regs->ARM_pc;
+ if (extern_timer_isr) return extern_timer_isr(regs);
+
if (__ipipe_decr_ticks != __ipipe_mach_ticks_per_jiffy) {
unsigned long long next_date, now;
@@ -517,6 +539,15 @@ asmlinkage int __ipipe_grab_irq(int irq,
&ipipe_root_domain->cpudata[cpuid].status));
}
+void *ipipe_irq_handler = __ipipe_handle_irq;
+EXPORT_SYMBOL(ipipe_irq_handler);
+EXPORT_SYMBOL(__ipipe_tick_regs);
+__attribute__((regparm(3))) void do_notify_resume(struct pt_regs *, void *, __u32);
+EXPORT_SYMBOL(do_notify_resume);
+extern void *sys_call_table;
+EXPORT_SYMBOL(sys_call_table);
+extern void ret_from_intr(void);
+
EXPORT_SYMBOL(__ipipe_decr_ticks);
EXPORT_SYMBOL(__ipipe_decr_next);
EXPORT_SYMBOL(ipipe_critical_enter);
@@ -525,6 +556,7 @@ EXPORT_SYMBOL(ipipe_trigger_irq);
EXPORT_SYMBOL(ipipe_get_sysinfo);
EXPORT_SYMBOL(ipipe_tune_timer);
+EXPORT_SYMBOL_GPL(irq_desc);
EXPORT_SYMBOL_GPL(show_stack);
#ifndef MULTI_CPU
EXPORT_SYMBOL_GPL(cpu_do_switch_mm);
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91rm9200_time.c linux-2.6.20.13/arch/arm/mach-at91rm9200/at91rm9200_time.c
--- linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91rm9200_time.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/arch/arm/mach-at91rm9200/at91rm9200_time.c 2007-07-12 09:34:28.000000000 +0200
@@ -338,6 +338,22 @@ notrace unsigned long long __ipipe_mach_
EXPORT_SYMBOL(__ipipe_mach_get_tsc);
/*
+ * getter/setter available for easy use of local_tsc
+ */
+
+notrace unsigned long long __ipipe_get_tsc(void)
+{
+ return (&tsc[ipipe_processor_id()])->full;
+}
+EXPORT_SYMBOL(__ipipe_get_tsc);
+
+notrace void __ipipe_set_tsc(unsigned long long value)
+{
+ (&tsc[ipipe_processor_id()])->full = value;
+}
+EXPORT_SYMBOL(__ipipe_set_tsc);
+
+/*
* Reprogram the timer
*/
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91sam9261.c linux-2.6.20.13/arch/arm/mach-at91rm9200/at91sam9261.c
--- linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91sam9261.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/arch/arm/mach-at91rm9200/at91sam9261.c 2007-08-24 17:18:07.000000000 +0200
@@ -287,7 +287,7 @@ static unsigned int at91sam9261_default_
/* Give the highest priority to TC, since they are used as timer interrupt by
I-pipe. */
7, /* Advanced Interrupt Controller */
- 7, /* System Peripherals */
+ 6, /* System Peripherals */
0, /* Parallel IO Controller A */
0, /* Parallel IO Controller B */
0, /* Parallel IO Controller C */
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.20.13/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- linux-2.6.20.13-clean/arch/arm/mach-at91rm9200/at91sam926x_time.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/arch/arm/mach-at91rm9200/at91sam926x_time.c 2007-07-12 09:34:28.000000000 +0200
@@ -325,6 +325,22 @@ notrace unsigned long long __ipipe_mach_
EXPORT_SYMBOL(__ipipe_mach_get_tsc);
/*
+ * getter/setter available for easy use of local_tsc
+ */
+
+notrace unsigned long long __ipipe_get_tsc(void)
+{
+ return (&tsc[ipipe_processor_id()])->full;
+}
+EXPORT_SYMBOL(__ipipe_get_tsc);
+
+notrace void __ipipe_set_tsc(unsigned long long value)
+{
+ (&tsc[ipipe_processor_id()])->full = value;
+}
+EXPORT_SYMBOL(__ipipe_set_tsc);
+
+/*
* Reprogram the timer
*/
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/include/asm-arm/ipipe.h linux-2.6.20.13/include/asm-arm/ipipe.h
--- linux-2.6.20.13-clean/include/asm-arm/ipipe.h 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/include/asm-arm/ipipe.h 2007-07-13 14:05:00.000000000 +0200
@@ -70,7 +70,8 @@ do { \
#define IPIPE_NR_FAULTS 8
/* Pseudo-vectors used for kernel events */
-#define IPIPE_FIRST_EVENT IPIPE_NR_FAULTS
+#define IPIPE_FIRST_EVENT IPIPE_NR_FAULTS + 2 /* on x86, HAL_SCHEDULE_TAIL = IPIPE_FIRST_EVENT - 2 is not used
+ * on ARM, this trap can be used by VFP, so we add an offset on IPIPE_FIRST_EVENT */
#define IPIPE_EVENT_SYSCALL (IPIPE_FIRST_EVENT)
#define IPIPE_EVENT_SCHEDULE (IPIPE_FIRST_EVENT + 1)
#define IPIPE_EVENT_SIGWAKE (IPIPE_FIRST_EVENT + 2)
@@ -166,6 +167,10 @@ void __ipipe_init_platform(void);
void __ipipe_enable_irqdesc(unsigned irq);
+void __ipipe_enable_depth(unsigned irq);
+
+void __ipipe_disable_depth(unsigned irq);
+
void __ipipe_enable_pipeline(void);
void __ipipe_do_IRQ(int irq,
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/include/asm-arm/irqflags.h linux-2.6.20.13/include/asm-arm/irqflags.h
--- linux-2.6.20.13-clean/include/asm-arm/irqflags.h 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/include/asm-arm/irqflags.h 2007-08-06 09:59:29.000000000 +0200
@@ -170,13 +170,13 @@ void __ipipe_restore_root(unsigned long
} while (0)
#define local_irq_save_hw(x) do { \
local_save_flags_hw(x); \
- if (raw_irqs_disabled_flags(x)) { \
+ if (!raw_irqs_disabled_flags(x)) { \
local_irq_disable_hw_notrace(); \
ipipe_trace_begin(0x80000001); \
} \
} while (0)
#define local_irq_restore_hw(x) do { \
- if (raw_irqs_disabled_flags(x)) \
+ if (!raw_irqs_disabled_flags(x)) \
ipipe_trace_end(0x80000001); \
local_irq_restore_hw_notrace(x); \
} while (0)
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/include/asm-arm/system.h linux-2.6.20.13/include/asm-arm/system.h
--- linux-2.6.20.13-clean/include/asm-arm/system.h 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/include/asm-arm/system.h 2007-07-12 09:34:28.000000000 +0200
@@ -347,6 +347,46 @@ static inline unsigned long __xchg(unsig
extern void disable_hlt(void);
extern void enable_hlt(void);
+/*
+ * We only implement cmpxchg in ASM on ARMv6 where we have LDREX/STREX
+ * available, and we only implement it for word-sized exchanges
+ */
+#if __LINUX_ARM_ARCH__ >= 6
+extern void __bad_cmpxchg(volatile void *, int);
+
+#define cmpxchg(ptr, old, new) \
+({ \
+ __typeof__ (ptr) ____p = (ptr); \
+ __typeof__(*ptr) ____old = (old); \
+ __typeof__(*ptr) ____new = (new); \
+ __typeof__(*ptr) ____oldval; \
+ __typeof__(*ptr) ____res; \
+ \
+ switch (sizeof(____res)) { \
+ case 4: \
+ do { \
+ __asm__ __volatile__("@ cmpxchg\n" \
+ "ldrex %1, [%2]\n" \
+ "mov %0, #0\n" \
+ "teq %1, %3\n" \
+ "strexeq %0, %4, [%2]\n" \
+ : "=&r" (____res), "=&r" (____oldval) \
+ : "r" (____p), "Ir" (____old), "r" (____new) \
+ : "cc"); \
+ } while(____res); \
+ break; \
+ default: \
+ __bad_cmpxchg(____p, sizeof(____res)); \
+ ____oldval = 0; \
+ break; \
+ } \
+ ____oldval; \
+})
+
+#else
+#include <asm-generic/cmpxchg.h>
+#endif
+
#endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x)
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/include/asm-arm/thread_info.h linux-2.6.20.13/include/asm-arm/thread_info.h
--- linux-2.6.20.13-clean/include/asm-arm/thread_info.h 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/include/asm-arm/thread_info.h 2007-07-12 09:34:28.000000000 +0200
@@ -143,6 +143,7 @@ extern void iwmmxt_task_switch(struct th
#define TIF_NOTIFY_RESUME 0
#define TIF_SIGPENDING 1
#define TIF_NEED_RESCHED 2
+#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
#define TIF_SYSCALL_TRACE 8
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
@@ -155,6 +156,7 @@ extern void iwmmxt_task_switch(struct th
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/include/asm-generic/cmpxchg.h linux-2.6.20.13/include/asm-generic/cmpxchg.h
--- linux-2.6.20.13-clean/include/asm-generic/cmpxchg.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.13/include/asm-generic/cmpxchg.h 2007-07-12 09:34:28.000000000 +0200
@@ -0,0 +1,46 @@
+/* Generic cmpxchg for those arches that don't implement it themselves
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#ifndef _ASM_GENERIC_CMPXCHG_H
+#define _ASM_GENERIC_CMPXCHG_H
+
+#if !defined(cmpxchg) && !defined(CONFIG_SMP)
+
+/**
+ * cmpxchg - Atomically conditionally exchange one value for another.
+ * @ptr - Pointer to the value to be altered.
+ * @old - The value to change from.
+ * @new - The value to change to.
+ *
+ * This function atomically compares the current value at the word pointed to
+ * by @ptr, and if it's the same as @old, changes it to @new. If it's not the
+ * same then it's left unchanged.
+ *
+ * The value that was in the word pointed to by @ptr is returned, whether or
+ * not it was changed to @new.
+ */
+#define cmpxchg(ptr, old, new) \
+({ \
+ unsigned long ____flags; \
+ __typeof__ (ptr) ____p = (ptr); \
+ __typeof__(*ptr) ____old = (old); \
+ __typeof__(*ptr) ____new = (new); \
+ __typeof__(*ptr) ____res; \
+ raw_local_irq_save(____flags); \
+ ____res = *____p; \
+ if (likely(____res == (____old))) \
+ *____p = (____new); \
+ raw_local_irq_restore(____flags); \
+ ____res; \
+})
+
+#endif /* !cmpxchg && !SMP */
+#endif /* _ASM_GENERIC_CMPXCHG_H */
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/kernel/ipipe/core.c linux-2.6.20.13/kernel/ipipe/core.c
--- linux-2.6.20.13-clean/kernel/ipipe/core.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/kernel/ipipe/core.c 2007-07-30 14:10:11.000000000 +0200
@@ -531,10 +531,12 @@ int ipipe_virtualize_irq(struct ipipe_do
if ((modemask & IPIPE_STICKY_MASK) != 0)
modemask |= IPIPE_HANDLE_MASK;
- } else
+ } else {
modemask &=
~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK |
IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK);
+ __ipipe_enable_depth(irq);
+ }
if (acknowledge == NULL && !ipipe_virtual_irq_p(irq))
/* Acknowledge handler unspecified for a hw interrupt:
@@ -548,6 +550,7 @@ int ipipe_virtualize_irq(struct ipipe_do
if (irq < NR_IRQS && handler != NULL && !ipipe_virtual_irq_p(irq)) {
__ipipe_enable_irqdesc(irq);
+ __ipipe_disable_depth(irq);
if ((modemask & IPIPE_ENABLE_MASK) != 0) {
if (ipd != ipipe_current_domain) {
@@ -617,6 +620,12 @@ int ipipe_control_irq(unsigned irq, unsi
int fastcall __ipipe_dispatch_event (unsigned event, void *data)
{
+ extern void *ipipe_irq_handler;
+ void *handler;
+ if (ipipe_irq_handler != __ipipe_handle_irq && (handler = ipipe_root_domain->evhand[event])) {
+ return ((int (*)(unsigned long, void *))handler)(event, data);
+ } else {
+
struct ipipe_domain *start_domain, *this_domain, *next_domain;
ipipe_event_handler_t evhand;
struct list_head *pos, *npos;
@@ -677,7 +686,7 @@ int fastcall __ipipe_dispatch_event (uns
ipipe_unlock_cpu(flags);
return !propagate;
-}
+} }
/*
* __ipipe_dispatch_wired -- Wired interrupt dispatcher. Wired
@@ -1443,3 +1452,4 @@ EXPORT_SYMBOL(ipipe_get_ptd);
EXPORT_SYMBOL(ipipe_set_irq_affinity);
EXPORT_SYMBOL(ipipe_send_ipi);
EXPORT_SYMBOL(__ipipe_schedule_irq);
+EXPORT_SYMBOL(__ipipe_sync_stage);
diff -NaurdpbB -X nodiff linux-2.6.20.13-clean/kernel/sched.c linux-2.6.20.13/kernel/sched.c
--- linux-2.6.20.13-clean/kernel/sched.c 2007-07-12 11:44:04.000000000 +0200
+++ linux-2.6.20.13/kernel/sched.c 2007-08-23 13:44:00.000000000 +0200
@@ -1845,6 +1845,12 @@ context_switch(struct rq *rq, struct tas
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;
+#ifdef CONFIG_IPIPE
+if (!rq) {
+ switch_mm(oldmm, next->active_mm, next);
+ if (!mm) enter_lazy_tlb(oldmm, next);
+} else {
+#endif
if (!mm) {
next->active_mm = oldmm;
atomic_inc(&oldmm->mm_count);
@@ -1857,6 +1863,9 @@ context_switch(struct rq *rq, struct tas
WARN_ON(rq->prev_mm);
rq->prev_mm = oldmm;
}
+#ifdef CONFIG_IPIPE
+}
+#endif
/*
* Since the runqueue lock will be released by the next
* task (which is an invalid locking op but in the case
@@ -1864,12 +1873,19 @@ context_switch(struct rq *rq, struct tas
* do an early lockdep release here:
*/
#ifndef __ARCH_WANT_UNLOCKED_CTXSW
+#ifdef CONFIG_IPIPE
+if (rq)
+#endif /* CONFIG_IPIPE */
spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
#endif
/* Here we just switch the register state and the stack. */
switch_to(prev, next, prev);
+#ifdef CONFIG_IPIPE
+ current->ptd[IPIPE_ROOT_NPTDKEYS - 1] = prev;
+#endif /* CONFIG_IPIPE */
+
return prev;
}
@@ -3567,6 +3583,9 @@ switch_tasks:
barrier();
if (task_hijacked(prev))
return;
+ #ifdef CONFIG_IPIPE
+ __ipipe_dispatch_event(IPIPE_FIRST_EVENT - 2, 0);
+ #endif /* CONFIG_IPIPE */
/*
* this_rq must be evaluated again because prev may have moved
* CPUs since it called schedule(), thus the 'rq' on its stack
@@ -7115,6 +7134,7 @@ int ipipe_reenter_root (struct task_stru
return 0;
}
+EXPORT_SYMBOL(context_switch);
EXPORT_SYMBOL(ipipe_reenter_root);
#endif /* CONFIG_IPIPE */

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