Compare commits
1 commit
master
...
remove-non
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04c0b06102 |
1082 changed files with 273406 additions and 32745 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -31,7 +31,6 @@ addons/drivers/16550A/FORCE
|
|||
# Generated Makefiles
|
||||
GNUmakefile.in
|
||||
GNUmakefile
|
||||
Makefile.in
|
||||
Makefile
|
||||
|
||||
# Config Temp Files
|
||||
|
|
|
|||
105
GNUmakefile.am
105
GNUmakefile.am
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
|
@ -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
14
README.maintainer
Normal 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.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
59
addons/comedi/GNUmakefile.am
Normal file
59
addons/comedi/GNUmakefile.am
Normal 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
|
||||
10
addons/comedi/Makefile.kbuild
Normal file
10
addons/comedi/Makefile.kbuild
Normal 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
243
addons/comedi/README
Normal 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
|
||||
741
addons/comedi/kcomedi-module.c
Normal file
741
addons/comedi/kcomedi-module.c
Normal 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
28
addons/comedi/kcomedi.c
Normal 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>
|
||||
117
addons/comedi/patchlinuxcomedi
Normal file
117
addons/comedi/patchlinuxcomedi
Normal 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
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
227
addons/cpp/GNUmakefile.am
Normal 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
92
addons/cpp/bits.cc
Normal 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
154
addons/cpp/bits.h
Normal 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
77
addons/cpp/bits_init.c
Normal 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
162
addons/cpp/builtin.c
Normal 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
51
addons/cpp/cond.cc
Normal 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
52
addons/cpp/cond.h
Normal 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
140
addons/cpp/count.cc
Normal 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
114
addons/cpp/count.h
Normal 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
237
addons/cpp/crt.c
Normal 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(¤t->sigmask_lock);
|
||||
tmpsig = current->blocked;
|
||||
siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
|
||||
recalc_sigpending(current);
|
||||
spin_unlock_irq(¤t->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
49
addons/cpp/cs.cc
Normal 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
65
addons/cpp/init.c
Normal 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
227
addons/cpp/iostream.cc
Normal 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
94
addons/cpp/iostream.h
Normal 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
|
||||
32
addons/cpp/linux_wrapper.c
Normal file
32
addons/cpp/linux_wrapper.c
Normal 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;
|
||||
}
|
||||
38
addons/cpp/linux_wrapper.h
Normal file
38
addons/cpp/linux_wrapper.h
Normal 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
164
addons/cpp/mbx.cc
Normal 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
117
addons/cpp/mbx.h
Normal 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
25
addons/cpp/module.cc
Normal 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
38
addons/cpp/module.h
Normal 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
48
addons/cpp/mutex.cc
Normal 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
66
addons/cpp/mutex.h
Normal 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
64
addons/cpp/new.h
Normal 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
53
addons/cpp/rtai_cpp.h
Normal 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
|
||||
272
addons/cpp/rtai_pqueue_wrapper.h
Normal file
272
addons/cpp/rtai_pqueue_wrapper.h
Normal 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_
|
||||
78
addons/cpp/rtai_pthread_int_wrapper.h
Normal file
78
addons/cpp/rtai_pthread_int_wrapper.h
Normal 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_
|
||||
304
addons/cpp/rtai_pthread_wrapper.h
Normal file
304
addons/cpp/rtai_pthread_wrapper.h
Normal 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
95
addons/cpp/rtai_wrapper.c
Normal 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
49
addons/cpp/rtai_wrapper.h
Normal 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
77
addons/cpp/rtf.cc
Normal 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
78
addons/cpp/rtf.h
Normal 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
51
addons/cpp/rtf_init.c
Normal 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
112
addons/cpp/sem.cc
Normal 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
106
addons/cpp/sem.h
Normal 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
336
addons/cpp/task.cc
Normal 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
137
addons/cpp/task.h
Normal 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
177
addons/cpp/tbx.cc
Normal 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
159
addons/cpp/tbx.h
Normal 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
83
addons/cpp/tbx_init.c
Normal 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
142
addons/cpp/time.cc
Normal 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
124
addons/cpp/time.h
Normal 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
81
addons/cpp/tld_key.c
Normal 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
55
addons/cpp/tld_key.h
Normal 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
61
addons/cpp/trace.cc
Normal 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
73
addons/cpp/trace.h
Normal 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
68
addons/cpp/watchdog.cc
Normal 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
57
addons/cpp/watchdog.h
Normal 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
|
||||
51
addons/cpp/watchdog_init.c
Normal file
51
addons/cpp/watchdog_init.c
Normal 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)
|
||||
|
||||
1206
addons/drivers/16550A/16550A.c
Normal file
1206
addons/drivers/16550A/16550A.c
Normal file
File diff suppressed because it is too large
Load diff
213
addons/drivers/16550A/16550A_io.h
Normal file
213
addons/drivers/16550A/16550A_io.h
Normal 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;
|
||||
}
|
||||
}
|
||||
288
addons/drivers/16550A/16550A_pci.h
Normal file
288
addons/drivers/16550A/16550A_pci.h
Normal 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 */
|
||||
389
addons/drivers/16550A/16550A_pnp.h
Normal file
389
addons/drivers/16550A/16550A_pnp.h
Normal 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) */
|
||||
57
addons/drivers/16550A/GNUmakefile.am
Normal file
57
addons/drivers/16550A/GNUmakefile.am
Normal 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
|
||||
10
addons/drivers/16550A/Makefile.kbuild
Normal file
10
addons/drivers/16550A/Makefile.kbuild
Normal 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)
|
||||
11
addons/drivers/GNUmakefile.am
Normal file
11
addons/drivers/GNUmakefile.am
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
OPTDIRS =
|
||||
|
||||
if CONFIG_RTAI_DRIVERS_SERIAL
|
||||
OPTDIRS += serial
|
||||
endif
|
||||
|
||||
if CONFIG_RTAI_DRIVERS_16550A
|
||||
OPTDIRS += 16550A
|
||||
endif
|
||||
|
||||
SUBDIRS = $(OPTDIRS)
|
||||
46
addons/drivers/serial/GNUmakefile.am
Normal file
46
addons/drivers/serial/GNUmakefile.am
Normal 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
|
||||
9
addons/drivers/serial/Makefile.kbuild
Normal file
9
addons/drivers/serial/Makefile.kbuild
Normal 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)
|
||||
433
addons/drivers/serial/README
Normal file
433
addons/drivers/serial/README
Normal 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.
|
||||
418
addons/drivers/serial/rtai_serial.h
Normal file
418
addons/drivers/serial/rtai_serial.h
Normal 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 */
|
||||
1334
addons/drivers/serial/serial.c
Normal file
1334
addons/drivers/serial/serial.c
Normal file
File diff suppressed because it is too large
Load diff
118
addons/drivers/serial/serialP.h
Normal file
118
addons/drivers/serial/serialP.h
Normal 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 */
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
|
@ -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 */
|
||||
13
autogen.sh
13
autogen.sh
|
|
@ -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" "$@"
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
3
base/arch/arm/GNUmakefile.am
Normal file
3
base/arch/arm/GNUmakefile.am
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
SUBDIRS = hal
|
||||
|
||||
EXTRA_DIST = Kconfig defconfig patches
|
||||
538
base/arch/arm/Kconfig
Normal file
538
base/arch/arm/Kconfig
Normal 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
77
base/arch/arm/defconfig
Normal 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
|
||||
63
base/arch/arm/hal/GNUmakefile.am
Normal file
63
base/arch/arm/hal/GNUmakefile.am
Normal 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
|
||||
8
base/arch/arm/hal/Makefile.kbuild
Normal file
8
base/arch/arm/hal/Makefile.kbuild
Normal 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
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
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
854
base/arch/arm/hal/hal.piped
Normal 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*)®s->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);
|
||||
127
base/arch/arm/hal/mach-at91/at91-timer.c
Normal file
127
base/arch/arm/hal/mach-at91/at91-timer.c
Normal 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);
|
||||
}
|
||||
144
base/arch/arm/hal/mach-ep9301/ep9301-timer.c
Normal file
144
base/arch/arm/hal/mach-ep9301/ep9301-timer.c
Normal 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);
|
||||
}
|
||||
123
base/arch/arm/hal/mach-imx/imx-timer.c
Normal file
123
base/arch/arm/hal/mach-imx/imx-timer.c
Normal 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);
|
||||
}
|
||||
139
base/arch/arm/hal/mach-pxa/pxa-timer.c
Normal file
139
base/arch/arm/hal/mach-pxa/pxa-timer.c
Normal 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);
|
||||
}
|
||||
160
base/arch/arm/patches/README
Normal file
160
base/arch/arm/patches/README
Normal 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!
|
||||
|
||||
181
base/arch/arm/patches/at91_2.6.20.13-at91sam9263.patch
Normal file
181
base/arch/arm/patches/at91_2.6.20.13-at91sam9263.patch
Normal 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__ */
|
||||
|
||||
424
base/arch/arm/patches/at91_2.6.20.13.patch
Normal file
424
base/arch/arm/patches/at91_2.6.20.13.patch
Normal 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
Loading…
Reference in a new issue