diff --git a/Bearbeiten2.c b/Bearbeiten2.c index 87b21f6..f7c8931 100644 --- a/Bearbeiten2.c +++ b/Bearbeiten2.c @@ -3,6 +3,10 @@ #include #include +#include "include/rtai_lxrt.h" +#include "include/rtai_modbus.h" +#include "include/rtai_sem.h" +#include "include/rtai_mbx.h" #define SENSOR_PART_TURNTABLE 1<<0 #define SENSOR_PART_DRILL 1<<1 @@ -24,21 +28,40 @@ MODULE_LICENSE("GPL"); static RT_TASK turntable_task, drill_task, tester_task, output_task; -static MBX drill_mbx, tester_mbx, output_mbx; +static MBX tester_mbx, output_mbx; static SEM semaphore; +int connection; + char node[] = "modbus-node"; +void fail() { + rt_modbus_disconnect(connection); + rt_task_delete(&turntable_task); + rt_task_delete(&tester_task); + rt_task_delete(&drill_task); + rt_task_delete(&output_task); + + rt_mbx_delete(&tester_mbx); + rt_mbx_delete(&output_mbx); + rt_sem_delete(&semaphore); + + stop_rt_timer(); + + rt_printk("failed to read/send Modbus message.\n"); + rt_printk("module needs to be restarted.\n"); +} + /** - * read all bits of the specified type + * readData all bits of the specified type * this function is *not* thread safe. * @param type (DIGITAL_IN, DIGITAL_OUT, ANALOG_IN, ANALOG_OUT) * @param connection modbus connection id * @param result value to write the result to * @return status code(0: success, 1: failure) */ -int readAll(int type, int connection, int *result) { - return rt_modbus_get(fd_node, type, 0, (unsigned short *) &result)); +int readAll(int type, int *result) { + return rt_modbus_get(connection, type, 0, (unsigned short *) &result)); } /** @@ -49,10 +72,10 @@ int readAll(int type, int connection, int *result) { * @param result value to write the result to * @return status code(0: success, 1: failure) */ -int read(int connection, int part, int *result) { +int readData(int part, int *result) { rt_sem_wait(&semaphore); int value; - int code = readAll(DIGITAL_IN, connection, &value); + int code = readAll(DIGITAL_IN, &value); *result = (value & part) != 0; rt_sem_signal(&semaphore); return code; @@ -63,16 +86,15 @@ int read(int connection, int part, int *result) { * this function is thread safe. * @param connection modbus connection id * @param actor bitmask of the actor to disable - * @return status code(0: success, 1: failure) */ -int disable(int connection, int actor) { +void disable(int actor) { rt_sem_wait(&semaphore); int value; - int code = readAll(DIGITAL_OUT, connection, &value); - if (code) return code; - int result = rt_modbus_set(connection, DIGITAL_OUT, output &= ~actor) + int code = readAll(DIGITAL_OUT, &value); + if(code) fail(); + int result = rt_modbus_set(connection, DIGITAL_OUT, value &= ~actor) rt_sem_signal(&semaphore); - return result; + if (result) fail(); } /** @@ -80,155 +102,99 @@ int disable(int connection, int actor) { * this function is thread safe. * @param connection modbus connection id * @param actor bitmask of the actor to enable - * @return status code (0: success, 1: failure) */ -int enable(int connection, int actor) { +void enable(int actor) { rt_sem_wait(&semaphore); int output; - int code = readAll(DIGITAL_OUT, connection, &output); - if (code) return code; + int code = readAll(DIGITAL_OUT, &output); + if (code) fail(); int result = rt_modbus_set(connection, DIGITAL_OUT, output |= actor) rt_sem_signal(&semaphore); - return result; + if(result) fail(); } -void sleep() { +void sleepStuff() { rt_sleep(1000 * nano2count(1000000)); } static void turntable(long x) { - int connection; - - rt_printk("turntable: task started\n"); - - if ((connection = rt_modbus_connect(node)) == -1) { - rt_printk("turntable: could not connect to %s\n", node); - return; - } rt_printk("turntable: MODBUS communication opened\n"); - disable(connection, ACTOR_TURNTABLE); + disable(ACTOR_TURNTABLE); while (1) { int partOnTable; - if (read(connection, SENSOR_PART_TURNTABLE, &partOnTable)) goto fail; - + readData(SENSOR_PART_TURNTABLE, &partOnTable); if (partOnTable) { - if (enable(connection, ACTOR_TURNTABLE)) goto fail; + enable(ACTOR_TURNTABLE); } else { - if (disable(connection, ACTOR_TURNTABLE)) goto fail; + disable(ACTOR_TURNTABLE); } rt_task_resume(&drill_task); rt_task_resume(&tester_task); rt_task_resume(&output_task); - - //rt_sleep(1000 * nano2count(1000000)); } -/* Aufraeumen */ - fail: - rt_modbus_disconnect(connection); - rt_printk("turntable: task exited with failure\n"); } static void drill(long x) { - int connection; - rt_printk("drill: task started\n"); - if ((connection = rt_modbus_connect(node)) == -1) { - rt_printk("drill: could not connect to %s\n", node); - return; - } rt_printk("drill: MODBUS communication opened\n"); - disable(connection, ACTOR_DRILL); - disable(connection, ACTOR_PART_HOLD); - disable(connection, ACTOR_DRILL_DOWN); + disable(ACTOR_DRILL); + disable(ACTOR_PART_HOLD); + disable(ACTOR_DRILL_DOWN); - enable(connection, ACTOR_DRILL_UP); + enable(ACTOR_DRILL_UP); + rt_sem_wait(&semaphore); int drill_up = 0; - if (read(connection, SENSOR_DRILL_UP, drill_up)) goto fail; + readData(SENSOR_DRILL_UP, drill_up); if (!drill_up) { do { - read(connection, SENSOR_DRILL_UP, drill_up); + readData(SENSOR_DRILL_UP, drill_up); } while (drill_up == 0); } - disable(connection, ACTOR_DRILL_UP); + rt_sem_signal(&semaphore); + disable(ACTOR_DRILL_UP); while (1) { - sleep(); + sleepStuff(); } - - - fail: - rt_modbus_disconnect(connection); - rt_printk("drill: task exited with failure\n"); } static void tester(long x) { - int connection; - - rt_printk("tester: task started\n"); - if ((connection = rt_modbus_connect(node)) == -1) { - rt_printk("tester: could not connect to %s\n", node); - return; - } while (1) { - sleep(); + sleepStuff(); } - - - fail: - rt_modbus_disconnect(connection); - rt_printk("tester: task exited with failure\n"); } static void output(long x) { - int connection; - - rt_printk("output: task started\n"); - if ((connection = rt_modbus_connect(node)) == -1) { - rt_printk("output: could not connect to %s\n", node); - return; - } - while (1) { - sleep(); + sleepStuff(); } - - - fail: - rt_modbus_disconnect(connection); - rt_printk("output: task exited with failure\n"); -} - -static void __exit - -example_exit(void) { - rt_task_delete(&turntable_task); - rt_task_delete(&drill_task); - rt_task_delete(&tester_task); - rt_task_delete(&output_task); - stop_rt_timer(); - rt_sem_delete(&semaphore); - printk("module Bearbeiten2 unloaded\n"); } static int __init - example_init(void) { rt_set_oneshot_mode(); start_rt_timer(0); modbus_init(); + + rt_printk("init: task started\n"); + if ((connection = rt_modbus_connect(node)) == -1) { + rt_printk("init: could not connect to %s\n", node); + return; + } + rt_sem_init(&semaphore, 1); - if (rt_task_init(&turntable_task, turntable, 0, 1024, 0, 0, NULL)) { + if (rt_task_init(&turntable_task, turntable, 0, 1024, 10, 0, NULL)) { printk("turntable: cannot initialize task\n"); goto fail; } @@ -254,5 +220,16 @@ example_init(void) { return (1); } +static void __exit +example_exit(void) { + rt_task_delete(&turntable_task); + rt_task_delete(&drill_task); + rt_task_delete(&tester_task); + rt_task_delete(&output_task); + stop_rt_timer(); + rt_sem_delete(&semaphore); + printk("module Bearbeiten2 unloaded\n"); +} + module_exit(example_exit) module_init(example_init) diff --git a/CMakeLists.txt b/CMakeLists.txt index d78c7ef..d9819df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.3) project(Echtzeitdatenverarbeitung) +SET(CMAKE_C_STANDARD C99) + +include_directories("include") add_executable(Bearbeiten2 Bearbeiten2.c) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02f3591 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +![SDL Diagramm](https://files.joethei.space/documentation/diagram.png) \ No newline at end of file diff --git a/diagram.puml b/diagram.puml new file mode 100644 index 0000000..27de6e3 --- /dev/null +++ b/diagram.puml @@ -0,0 +1,96 @@ +@startuml + +partition Drehteller { + +start + +:Drehteller ausschalten; +while(true) is (true) + if(Sensor aktiv ?) then (true) + :drehen an; + else (false) + :drehen aus; + endif + +endwhile (false) +stop +} + +partition Prüfer { + +start +:Prüfer einfahren; +while(Dauerschleife) is (true) + if(Werkstück vorhanden ?) then (true) + :Prüfer ausfahren; + if(Werkstück Normallage ?) then (true) + :Bohrer(on)> + else (false) + :Bohrer(off)> + endif + :Prüfer einfahren; + else (false) + endif + +endwhile (false) +stop +} + +partition Bohrer { + +start +:Bohrer ausschalten; +:Bohrer hochfahren; +:Werkstück loslassen; +while(Dauerschleife) is (true) + +if(Werkstück vorhanden?) then(true) + :Bohrer< + :Auswerfer> + if(Normallage) then(true) + :Werkstück festhalten; + :Bohrer anschalten; + :Bohrer herunterfahren; + if(Bohrer unten) then (true) + :sleepStuff 500ms; + :Bohrer hochfahren; + endif + + if(Bohrer oben) then (true) + :Bohrer ausschalten; + :Werkstück loslassen; + endif + else(false) + endif + +else (false) +endif + +endwhile(false) + +stop + +} + +partition Auswerfer { + +start +:Auswerfer einfahren; +while(Dauerschleife) is (true) + +:Auswerfer< +note right + oder eher ne if hier ? +end note +:Auswerfen; + +endwhile(false) + +stop + +} + + + + +@enduml \ No newline at end of file diff --git a/include/plantuml.jar b/include/plantuml.jar new file mode 100644 index 0000000..f98d595 Binary files /dev/null and b/include/plantuml.jar differ diff --git a/include/rtai.h b/include/rtai.h new file mode 100644 index 0000000..5089c30 --- /dev/null +++ b/include/rtai.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1999-2015 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_RTAI_H +#define _RTAI_RTAI_H + +#ifdef __KERNEL__ +#include +#endif /* __KERNEL__ */ + +#include + +#ifdef __KERNEL__ +// see: Computing Practices, ACM, vol. 31, n. 10, 1988, pgs 1192-1201. + +#define TWOPWR31M1 2147483647 // 2^31 - 1 + +static inline long next_rand(long rand) +{ + const long a = 16807; + const long m = TWOPWR31M1; + const long q = 127773; + const long r = 2836; + + long lo, hi; + + hi = rand/q; + lo = rand - hi*q; + rand = a*lo - r*hi; + if (rand <= 0) { + rand += m; + } + return rand; +} + +static inline long irandu(unsigned long range) +{ + static long seed = 783637; + const long m = TWOPWR31M1; + + seed = next_rand(seed); + return rtai_imuldiv(seed, range, m); +} +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_RTAI_H */ diff --git a/include/rtai_defs.h.in b/include/rtai_defs.h.in new file mode 100644 index 0000000..eb4be6b --- /dev/null +++ b/include/rtai_defs.h.in @@ -0,0 +1,26 @@ +/* + * Re-written and fixed by Alec Ari + * Copyright (C) 1999-2016 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef RTAI_DEFS_H +#define RTAI_DEFS_H + +#define RTAI_INSTALL_DIR "@prefix@" + +#endif /* RTAI_DEFS_H */ diff --git a/include/rtai_fifos.h b/include/rtai_fifos.h new file mode 100644 index 0000000..ef01c22 --- /dev/null +++ b/include/rtai_fifos.h @@ -0,0 +1,797 @@ +/** + * @ingroup fifos + * @ingroup fifos_ipc + * @ingroup fifos_sem + * @file + * + * Interface of the @ref fifos "RTAI FIFO module". + * + * @note Copyright © 1999-2003 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_FIFOS_H +#define _RTAI_FIFOS_H + +#include + +#define MAX_FIFOS 64 + +#define RTAI_FIFOS_MAJOR 150 + +#define RESET 1 +#define RESIZE 2 +#define RTF_SUSPEND_TIMED 3 +#define OPEN_SIZED 4 +#define READ_ALL_AT_ONCE 5 +#define READ_TIMED 6 +#define WRITE_TIMED 7 +#define RTF_SEM_INIT 8 +#define RTF_SEM_WAIT 9 +#define RTF_SEM_TRYWAIT 10 +#define RTF_SEM_TIMED_WAIT 11 +#define RTF_SEM_POST 12 +#define RTF_SEM_DESTROY 13 +#define SET_ASYNC_SIG 14 +#define EAVESDROP 19 +#define OVRWRITE 20 +#define READ_IF 21 +#define WRITE_IF 22 +#define RTF_NAMED_CREATE 23 + +#define RTF_GET_N_FIFOS 15 +#define RTF_GET_FIFO_INFO 16 +#define RTF_CREATE_NAMED 17 +#define RTF_NAME_LOOKUP 18 + +#define RTF_NAMELEN 15 + +struct rt_fifo_info_struct{ + unsigned int fifo_number; + unsigned int size; + unsigned int opncnt; + int avbs, frbs; + char name[RTF_NAMELEN+1]; +}; + +struct rt_fifo_get_info_struct{ + unsigned int fifo; + unsigned int n; + struct rt_fifo_info_struct *ptr; +}; + +#define FUN_FIFOS_LXRT_INDX 10 + +#define _CREATE 0 +#define _DESTROY 1 +#define _PUT 2 +#define _GET 3 +#define _RESET 4 +#define _RESIZE 5 +#define _SEM_INIT 6 +#define _SEM_DESTRY 7 +#define _SEM_POST 8 +#define _SEM_TRY 9 +#define _CREATE_NAMED 10 +#define _GETBY_NAME 11 +#define _OVERWRITE 12 +#define _PUT_IF 13 +#define _GET_IF 14 +#define _NAMED_CREATE 15 +#define _AVBS 16 +#define _FRBS 17 + +#ifdef __KERNEL__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int __rtai_fifos_init(void); + +void __rtai_fifos_exit(void); + +int rtf_init(void); + +typedef int (*rtf_handler_t)(unsigned int fifo, int rw); + +/* Attach a handler to an RT-FIFO. + * + * Allow function handler to be called when a user process reads or writes to + * the FIFO. When the function is called, it is passed the fifo number as the + * argument. + */ + +int rtf_create_handler(unsigned int fifo, /* RT-FIFO */ + void *handler /* function to be called */); + + +/** + * @ingroup fifos_ipc + * Extended fifo handler. + * + * The usage of X_FIFO_HANDLER(handler) allows to install an extended handler, + * i.e. one prototyped as: + * @code + * int (*handler)(unsigned int fifo, int rw); + * @endcode + * to allow the user to easily understand if the handler was called at fifo + * read (@a rw is 'r') or write (rw is 'w'). + */ +#define X_FIFO_HANDLER(handler) ((int (*)(unsigned int, int rw))(handler)) + +/* Create an RT-FIFO. + * + * An RT-FIFO fifo is created with initial size of size. + * Return value: On success, 0 is returned. On error, -1 is returned. + */ +#undef rtf_create +RTAI_SYSCALL_MODE int rtf_create(unsigned int fifo, int size); + +/* Create an RT-FIFO with a name and size. + * + * An RT-FIFO is created with a name of name, it will be allocated + * the first unused minor number and will have a user assigned size. + * Return value: On success, the allocated minor number is returned. + * On error, -errno is returned. + */ + +int rtf_named_create(const char *name, int size); + +/* Create an RT-FIFO with a name. + * + * An RT-FIFO is created with a name of name, it will be allocated + * the first unused minor number and will have a default size. + * Return value: On success, the allocated minor number is returned. + * On error, -errno is returned. + */ + +RTAI_SYSCALL_MODE int rtf_create_named(const char *name); + +/* Look up a named RT-FIFO. + * + * Find the RT-FIFO with the name name. + * Return value: On success, the minor number is returned. + * On error, -errno is returned. + */ + +RTAI_SYSCALL_MODE int rtf_getfifobyname(const char *name); + +/* Reset an RT-FIFO. + * + * An RT-FIFO fifo is reset by setting its buffer pointers to zero, so + * that any existing data is discarded and the fifo started anew like at its + * creation. + */ + +RTAI_SYSCALL_MODE int rtf_reset(unsigned int fifo); + +/* destroy an RT-FIFO. + * + * Return value: On success, 0 is returned. + */ + +RTAI_SYSCALL_MODE int rtf_destroy(unsigned int fifo); + + +/* Resize an RT-FIFO. + * + * Return value: size is returned on success. On error, a negative value + * is returned. + */ + +RTAI_SYSCALL_MODE int rtf_resize(unsigned int minor, int size); + + +/* Write to an RT-FIFO. + * + * Try to write count bytes to an FIFO. Returns the number of bytes written. + */ + +RTAI_SYSCALL_MODE int rtf_put(unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to write */); + + + +/* Write to an RT-FIFO, over writing if there is not enough space. + * + * Try to write count bytes to an FIFO. Returns 0. + */ + +RTAI_SYSCALL_MODE int rtf_ovrwr_put(unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to write */); + + + +/* Write atomically to an RT-FIFO. + * + * Try to write count bytes in block to an FIFO. Returns the number of bytes + * written. + */ + +extern RTAI_SYSCALL_MODE int rtf_put_if (unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to write */); + +/* Read from an RT-FIFO. + * + * Try to read count bytes from a FIFO. Returns the number of bytes read. + */ + +RTAI_SYSCALL_MODE int rtf_get(unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to read */); + + +/* Atomically read from an RT-FIFO. + * + * Try to read count bytes in a block from an FIFO. Returns the number of bytes read. + */ + +RTAI_SYSCALL_MODE int rtf_get_if(unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to read */); + + +/* + * Preview the an RT-FIFO content. + */ + +int rtf_evdrp(unsigned int fifo, /* RT-FIFO */ + void * buf, /* buffer address */ + int count /* number of bytes to read */); + +/* Open an RT-FIFO semaphore. + * + */ + +RTAI_SYSCALL_MODE int rtf_sem_init(unsigned int fifo, /* RT-FIFO */ + int value /* initial semaphore value */); + + +/* Post to an RT-FIFO semaphore. + * + */ + +RTAI_SYSCALL_MODE int rtf_sem_post(unsigned int fifo /* RT-FIFO */); + + +/* Try to acquire an RT-FIFO semaphore. + * + */ + +RTAI_SYSCALL_MODE int rtf_sem_trywait(unsigned int fifo /* RT-FIFO */); + + +/* Destroy an RT-FIFO semaphore. + * + */ + +RTAI_SYSCALL_MODE int rtf_sem_destroy(unsigned int fifo /* RT-FIFO */); + +#define rtf_sem_delete rtf_sem_destroy + + +/* Get an RT-FIFO free bytes in buffer. + * + */ + +RTAI_SYSCALL_MODE int rtf_get_frbs(unsigned int fifo /* RT-FIFO */); + +/* Just for compatibility with earlier rtai_fifos releases. No more bh and user +buffers. Fifos are now awakened immediately and buffers > 128K are vmalloced */ + +#define rtf_create_using_bh(fifo, size, bh_list) rtf_create(fifo, size) +#define rtf_create_using_bh_and_usr_buf(fifo, buf, size, bh_list) rtf_create(fifo, size) +#define rtf_destroy_using_usr_buf(fifo) rtf_destroy(fifo) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +RTAI_PROTO(int, rtf_create,(unsigned int fifo, int size)) +{ + struct { unsigned long fifo, size; } arg = { fifo, size }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _CREATE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_destroy,(unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _DESTROY, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_put,(unsigned int fifo, const void *buf, int count)) +{ + struct { unsigned long fifo; const void *buf; long count; } arg = { fifo, buf, count }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _PUT, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_put_if,(unsigned int fifo, const void *buf, int count)) +{ + struct { unsigned long fifo; const void *buf; long count; } arg = { fifo, buf, count }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _PUT_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_get,(unsigned int fifo, void *buf, int count)) +{ + struct { unsigned long fifo; void *buf; long count; } arg = { fifo, buf, count }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _GET, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_get_if,(unsigned int fifo, void *buf, int count)) +{ + struct { unsigned long fifo; void *buf; long count; } arg = { fifo, buf, count }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _GET_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_get_avbs, (unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _AVBS, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_get_frbs, (unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _FRBS, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_reset_lxrt,(unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _RESET, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_resize_lxrt,(unsigned int fifo, int size)) +{ + struct { unsigned long fifo, size; } arg = { fifo, size }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _RESIZE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_sem_init_lxrt,(unsigned int fifo, int value)) +{ + struct { unsigned long fifo, value; } arg = { fifo, value }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _SEM_INIT, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_sem_post_lxrt,(unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _SEM_POST, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_sem_trywait_lxrt,(unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _SEM_TRY, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_sem_destroy_lxrt,(unsigned int fifo)) +{ + struct { unsigned long fifo; } arg = { fifo }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _SEM_DESTRY, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_named_create_lxrt,(const char *name, int size)) +{ + int len; + char lname[len = strlen(name)]; + struct { char * name; long size; } arg = { lname, size }; + strncpy(lname, name, len); + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _NAMED_CREATE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_create_named_lxrt,(const char *name)) +{ + int len; + char lname[len = strlen(name)]; + struct { char * name; } arg = { lname }; + strncpy(lname, name, len); + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _CREATE_NAMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_getfifobyname_lxrt,(const char *name)) +{ + int len; + char lname[len = strlen(name)]; + struct { char * name; } arg = { lname }; + strncpy(lname, name, len); + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _GETBY_NAME, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_ovrwr_put,(unsigned int fifo, const void *buf, int count)) +{ + struct { unsigned long fifo; const void *buf; long count; } arg = { fifo, buf, count }; + return rtai_lxrt(FUN_FIFOS_LXRT_INDX, SIZARG, _OVERWRITE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rtf_reset,(int fd)) +{ + int ret = ioctl(fd, RESET); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_resize,(int fd, int size)) +{ + int ret = ioctl(fd, RESIZE, size); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Suspend a process for some time + * + * rtf_suspend_timed suspends a Linux process according to @a delay. + * + * @param fd is the file descriptor returned at fifo open, rtf_suspend_timed + * needs a fifo support. + * @param ms_delay is the timeout time in milliseconds. + * + * @note The standard, clumsy, way to achieve the same result is to use select + * with null file arguments, for long sleeps, with seconds resolution, sleep is + * also available. + */ +RTAI_PROTO(int, rtf_suspend_timed,(int fd, int ms_delay)) +{ + int ret = ioctl(fd, RTF_SUSPEND_TIMED, ms_delay); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Create a real-time FIFO + * + * rtf_open_sized is the equivalent of rtf_create() in user space; it creates a + * real-time fifo (RT-FIFO) of initial size @a size. + * + * @param size is the requested size for the fifo. + * + * The RT-FIFO is a character based mechanism to communicate among real-time + * tasks and ordinary Linux processes. The rtf_* functions are used by the + * real-time tasks; Linux processes use standard character device access + * functions such as read, write, and select. + * + * If this function finds an existing fifo of lower size it resizes it to the + * larger new size. Note that the same condition apply to the standard Linux + * device open, except that when it does not find any already existing fifo it + * creates it with a default size of 1K bytes. + * + * It must be remarked that practically any fifo size can be asked for. In + * fact if @a size is within the constraint allowed by kmalloc such a function + * is used, otherwise vmalloc is called, thus allowing any size that can fit + * into the available core memory. + * + * Multiple calls of this function are allowed, a counter is kept internally to + * track their number, and avoid destroying/closing a fifo that is still used. + * + * @return the usual Unix file descriptor on succes, to be used in standard reads + * and writes. + * @retval -ENOMEM if the necessary size could not be allocated for the RT-FIFO. + * + * @note In user space, the standard UNIX open acts like rtf_open_sized with a + * default 1K size. + */ +RTAI_PROTO(int, rtf_open_sized,(const char *dev, int perm, int size)) +{ + int fd; + + if ((fd = open(dev, perm)) < 0) { + return -errno; + } + if (ioctl(fd, RESIZE, size) < 0) { + close(fd); + return -errno; + } + return fd; +} + +RTAI_PROTO(int, rtf_evdrp,(int fd, void *buf, int count)) +{ + struct { void *buf; long count; } args = { buf, count }; + int ret = ioctl(fd, EAVESDROP, &args); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Read data from FIFO in user space, waiting for all of them + * + * rtf_read_all_at_once reads a block of data from a real-time fifo identified + * by the file descriptor @a fd blocking till all waiting at most @a count + * bytes are available, whichever option was used at the related device + * opening. + * + * @param fd is the file descriptor returned at fifo open. + * @param buf points the block of data to be written. + * @param count is the size in bytes of the buffer. + * + * @return the number of bytes read on success. + * @retval -EINVAL if @a fd refers to a not opened fifo. + */ +RTAI_PROTO(int, rtf_read_all_at_once,(int fd, void *buf, int count)) +{ + struct { void *buf; long count; } args = { buf, count }; + int ret = ioctl(fd, READ_ALL_AT_ONCE, &args); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Read data from FIFO in user space, with timeout. + * + * rtf_read_timed reads a block of data from a real-time fifo identified by the + * file descriptor @a fd waiting at most @a delay milliseconds to complete the + * operation. + * + * @param fd is the file descriptor returned at fifo open. + * @param buf points the block of data to be written. + * @param count is the size of the block in bytes. + * @param ms_delay is the timeout time in milliseconds. + * + * @return the number of bytes read is returned on success or timeout. Note that + * this value may be less than @a count if @a count bytes of free space is not + * available in the fifo or a timeout occured. + * @retval -EINVAL if @a fd refers to a not opened fifo. + * + * @note The standard, clumsy, Unix way to achieve the same result is to use + * select. + */ +RTAI_PROTO(int, rtf_read_timed,(int fd, void *buf, int count, int ms_delay)) +{ + struct { void *buf; long count, delay; } args = { buf, count, ms_delay }; + int ret = ioctl(fd, READ_TIMED, &args); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_read_if,(int fd, void *buf, int count)) +{ + struct { void *buf; long count; } args = { buf, count }; + int ret = ioctl(fd, READ_IF, &args); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Write data to FIFO in user space, with timeout. + * + * rtf_write_timed writes a block of data to a real-time fifo identified by the + * file descriptor @a fd waiting at most @æ delay milliseconds to complete the + * operation. + * + * @param fd is the file descriptor returned at fifo open. + * @param buf points the block of data to be written. + * @param count is the size of the block in bytes. + * @param ms_delay is the timeout time in milliseconds. + * + * @return the number of bytes written on succes. Note that this value may + * be less than @a count if @a count bytes of free space is not available in the + * fifo. + * @retval -EINVAL if @a fd refers to a not opened fifo. + * + * @note The standard, clumsy, Unix way to achieve the same result is to use + * select. + */ +RTAI_PROTO(int, rtf_write_timed,(int fd, void *buf, int count, int ms_delay)) +{ + struct { void *buf; long count, delay; } args = { buf, count, ms_delay }; + int ret = ioctl(fd, WRITE_TIMED, &args); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_overwrite,(int fd, void *buf, int count)) +{ + struct { void *buf; long count; } args = { buf, count }; + int ret = ioctl(fd, OVRWRITE, &args); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_write_if,(int fd, void *buf, int count)) +{ + struct { void *buf; long count; } args = { buf, count }; + int ret = ioctl(fd, WRITE_IF, &args); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_sem_init,(int fd, int value)) +{ + int ret = ioctl(fd, RTF_SEM_INIT, value); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_sem + * Take a semaphore. + * + * rtf_sem_wait waits for a event to be posted (signaled) to a semaphore. The + * semaphore value is set to tested and set to zero. If it was one + * rtf_sem_wait returns immediately. Otherwise the caller process is blocked and + * queued up in a priority order based on is POSIX real time priority. + * + * A process blocked on a semaphore returns when: + * - the caller task is in the first place of the waiting queue and somebody + * issues a rtf_sem_post; + * - an error occurs (e.g. the semaphore is destroyed). + * + * @param fd is the file descriptor returned by standard UNIX open in user space + * + * Since it is blocking rtf_sem_waitcannot be used both in kernel and user + * space. + * + * @retval 0 on success. + * @retval -EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo. + */ +RTAI_PROTO(int, rtf_sem_wait,(int fd)) +{ + int ret = ioctl(fd, RTF_SEM_WAIT); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_sem_trywait,(int fd)) +{ + int ret = ioctl(fd, RTF_SEM_TRYWAIT); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_sem + * Wait a semaphore with timeout + * + * rtf_sem_timed_wait is a timed version of the standard semaphore wait + * call. The semaphore value is tested and set to zero. If it was one + * rtf_sem_timed_wait returns immediately. Otherwise the caller process is + * blocked and queued up in a priority order based on is POSIX real time + * priority. + * + * A process blocked on a semaphore returns when: + * - the caller task is in the first place of the waiting queue and somebody + * issues a rtf_sem_post; + * - timeout occurs; + * - an error occurs (e.g. the semaphore is destroyed). + * + * @param fd is the file descriptor returned by standard UNIX open in user + * space. In case of timeout the semaphore value is set to one before return. + * @param ms_delay is in milliseconds and is relative to the Linux current time. + * + * Since it is blocking rtf_sem_timed_wait cannot be used both in kernel and + * user space. + * + * @retval 0 on success. + * @retval -EINVAL if fd_fifo refers to an invalid file descriptor or fifo. + */ +RTAI_PROTO(int, rtf_sem_timed_wait,(int fd, int ms_delay)) +{ + int ret = ioctl(fd, RTF_SEM_TIMED_WAIT, ms_delay); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_sem_post,(int fd)) +{ + int ret = ioctl(fd, RTF_SEM_POST); + return ret < 0 ? -errno : ret; +} + +RTAI_PROTO(int, rtf_sem_destroy,(int fd)) +{ + int ret = ioctl(fd, RTF_SEM_DESTROY); + return ret < 0 ? -errno : ret; +} + +/** + * @ingroup fifos_ipc + * Activate asynchronous notification of data availability + * + * rtf_set_async_sig activate an asynchronous signals to notify data + * availability by catching a user set signal signum. + * + * @param signum is a user chosen signal number to be used, default is SIGIO. + * + * @retval -EINVAL if fd refers to a not opened fifo. + */ +RTAI_PROTO(int, rtf_set_async_sig,(int fd, int signum)) +{ + int ret = ioctl(fd, SET_ASYNC_SIG, signum); + return ret < 0 ? -errno : ret; +} + +/* + * Support for named FIFOS : Ian Soanes (ians@zentropix.com) + * Based on ideas from Stuart Hughes and David Schleef + */ + +RTAI_PROTO_ALWAYS_INLINE(char *, rtf_getfifobyminor,(int minor, char *buf, int len)) +{ + snprintf(buf,len,CONFIG_RTAI_FIFOS_TEMPLATE,minor); + return buf; +} + +RTAI_PROTO(int, rtf_getfifobyname,(const char *name)) +{ + int fd, minor; + char nm[RTF_NAMELEN+1]; + + if (strlen(name) > RTF_NAMELEN) { + return -1; + } + if ((fd = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) { + return -errno; + } + strncpy(nm, name, RTF_NAMELEN+1); + minor = ioctl(fd, RTF_NAME_LOOKUP, nm); + close(fd); + return minor < 0 ? -errno : minor; +} + +RTAI_PROTO(int, rtf_named_create,(const char *name, int size)) +{ + int fd, minor; + char nm[RTF_NAMELEN+1]; + + if (strlen(name) > RTF_NAMELEN) { + return -1; + } + if ((fd = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) { + return -errno; + } + strncpy(nm, name, RTF_NAMELEN+1); + minor = ioctl(fd, RTF_NAMED_CREATE, nm, size); + close(fd); + return minor < 0 ? -errno : minor; +} + +RTAI_PROTO(int, rtf_create_named,(const char *name)) +{ + int fd, minor; + char nm[RTF_NAMELEN+1]; + + if (strlen(name) > RTF_NAMELEN) { + return -1; + } + if ((fd = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) { + return -errno; + } + strncpy(nm, name, RTF_NAMELEN+1); + minor = ioctl(fd, RTF_CREATE_NAMED, nm); + close(fd); + return minor < 0 ? -errno : minor; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_FIFOS_H */ diff --git a/include/rtai_hal_names.h b/include/rtai_hal_names.h new file mode 100644 index 0000000..de89f80 --- /dev/null +++ b/include/rtai_hal_names.h @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Paolo Mantegazza + * + * 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, see . + * + */ + + +#ifndef _RTAI_HAL_NAMES_H +#define _RTAI_HAL_NAMES_H + +#include + +#define TSKEXT0 0 +#define TSKEXT1 1 +#define TSKEXT2 2 +#define TSKEXT3 3 + +#define hal_processor_id ipipe_processor_id + +#define hal_domain_struct ipipe_domain +#define hal_root_domain ipipe_root_domain + +#define hal_critical_enter ipipe_critical_enter +#define hal_critical_exit ipipe_critical_exit + +#define hal_sysinfo_struct ipipe_sysinfo +#define hal_get_sysinfo ipipe_get_sysinfo + +#define hal_set_irq_affinity ipipe_set_irq_affinity + +#define hal_alloc_irq ipipe_alloc_virq +#define hal_free_irq ipipe_free_virq + +#define hal_reenter_root() __ipipe_reenter_root() + +#endif /* _RTAI_HAL_NAMES_H */ diff --git a/include/rtai_lxrt.h b/include/rtai_lxrt.h new file mode 100644 index 0000000..fd05204 --- /dev/null +++ b/include/rtai_lxrt.h @@ -0,0 +1,1494 @@ +/** + * @ingroup lxrt + * @file + * + * LXRT main header. + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999-2003 Paolo Mantegazza + * @note Copyright © 2019 Alec Ari + * + * 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, see . + * + * + * ACKNOWLEDGMENTS: + * Pierre Cloutier (pcloutier@poseidoncontrols.com) has suggested the 6 + * characters names and fixed many inconsistencies within this file. + */ + +/** + * @defgroup lxrt LXRT module. + * + * LXRT services (soft-hard real time in user space) + * + * LXRT is a module that allows you to use all the services made available by + * RTAI and its schedulers in user space, both for soft and hard real time. At + * the moment it is a feature youll find nowhere but with RTAI. For an + * explanation of how it works see + * @ref lxrt_faq "Pierre Cloutiers LXRT-INFORMED FAQs", and the explanation of + * @ref whatis_lxrt "the implementation of hard real time in user space" + * (contributed by: Pierre Cloutier, Paolo Mantegazza, Steve Papacharalambous). + * + * LXRT-INFORMED should be the production version of LXRT, the latter being the + * development version. So it can happen that LXRT-INFORMED could be lagging + * slightly behind LXRT. If you need to hurry to the services not yet ported to + * LXRT-INFORMED do it without pain. Even if you are likely to miss some useful + * services found only in LXRT-INFORMED, we release only when a feature is + * relatively stable. + * + * From what said above there should be no need for anything specific as all the + * functions you can use in user space have been already documented in this + * manual. There are however a few exceptions that need to be explained. + * + * Note also that, as already done for the shared memory services in user space, + * the function calls for Linux processes are inlined in the file + * rtai_lxrt.h. This approach has been preferred to a library since it is + * simpler, more effective, the calls are short and simple so that, even if it + * is likely that there can be more than just a few per process, they could + * never be charged of making codes too bigger. Also common to shared memory + * is the use of unsigned int to identify LXRT objects. If you want to use + * string identifiers the same support functions, i.e. nam2num() and + * num2nam(), can be used. + * + *@{*/ + +#ifndef _RTAI_LXRT_H +#define _RTAI_LXRT_H + +#include +#include + +// scheduler +#define YIELD 0 +#define SUSPEND 1 +#define RESUME 2 +#define MAKE_PERIODIC 3 +#define WAIT_PERIOD 4 +#define SLEEP 5 +#define SLEEP_UNTIL 6 +#define START_TIMER 7 +#define STOP_TIMER 8 +#define GET_TIME 9 +#define COUNT2NANO 10 +#define NANO2COUNT 11 +#define BUSY_SLEEP 12 +#define SET_PERIODIC_MODE 13 +#define SET_ONESHOT_MODE 14 +#define SIGNAL_HANDLER 15 +#define TASK_USE_FPU 16 +#define GET_TASK_INFO 17 // was LINUX_USE_FPU +#define HARD_TIMER_COUNT 18 +#define GET_TIME_NS 19 +#define GET_CPU_TIME_NS 20 +#define SET_RUNNABLE_ON_CPUS 21 +#define SET_RUNNABLE_ON_CPUID 22 +#define GET_TIMER_CPU 23 +#define START_RT_APIC_TIMERS 24 +#define HARD_TIMER_COUNT_CPUID 25 +#define COUNT2NANO_CPUID 26 +#define NANO2COUNT_CPUID 27 +#define GET_TIME_CPUID 28 +#define GET_TIME_NS_CPUID 29 +#define MAKE_PERIODIC_NS 30 +#define SET_SCHED_POLICY 31 +#define SET_RESUME_END 32 +#define SPV_RMS 33 +#define WAKEUP_SLEEPING 34 +#define CHANGE_TASK_PRIO 35 +#define SET_RESUME_TIME 36 +#define SET_PERIOD 37 +#define HARD_TIMER_RUNNING 38 + +// semaphores +#define TYPED_SEM_INIT 39 +#define SEM_DELETE 40 +#define NAMED_SEM_INIT 41 +#define NAMED_SEM_DELETE 42 +#define SEM_SIGNAL 43 +#define SEM_WAIT 44 +#define SEM_WAIT_IF 45 +#define SEM_WAIT_UNTIL 46 +#define SEM_WAIT_TIMED 47 +#define SEM_BROADCAST 48 +#define SEM_WAIT_BARRIER 49 +#define SEM_COUNT 50 +#define COND_WAIT 51 +#define COND_WAIT_UNTIL 52 +#define COND_WAIT_TIMED 53 +#define RWL_INIT 54 +#define RWL_DELETE 55 +#define NAMED_RWL_INIT 56 +#define NAMED_RWL_DELETE 57 +#define RWL_RDLOCK 58 +#define RWL_RDLOCK_IF 59 +#define RWL_RDLOCK_UNTIL 60 +#define RWL_RDLOCK_TIMED 61 +#define RWL_WRLOCK 62 +#define RWL_WRLOCK_IF 63 +#define RWL_WRLOCK_UNTIL 64 +#define RWL_WRLOCK_TIMED 65 +#define RWL_UNLOCK 66 +#define SPL_INIT 67 +#define SPL_DELETE 68 +#define NAMED_SPL_INIT 69 +#define NAMED_SPL_DELETE 70 +#define SPL_LOCK 71 +#define SPL_LOCK_IF 72 +#define SPL_LOCK_TIMED 73 +#define SPL_UNLOCK 74 + +// mail boxes +#define TYPED_MBX_INIT 75 +#define MBX_DELETE 76 +#define NAMED_MBX_INIT 77 +#define NAMED_MBX_DELETE 78 +#define MBX_SEND 79 +#define MBX_SEND_WP 80 +#define MBX_SEND_IF 81 +#define MBX_SEND_UNTIL 82 +#define MBX_SEND_TIMED 83 +#define MBX_RECEIVE 84 +#define MBX_RECEIVE_WP 85 +#define MBX_RECEIVE_IF 86 +#define MBX_RECEIVE_UNTIL 87 +#define MBX_RECEIVE_TIMED 88 +#define MBX_EVDRP 89 +#define MBX_OVRWR_SEND 90 + +// short intertask messages +#define SENDMSG 91 +#define SEND_IF 92 +#define SEND_UNTIL 93 +#define SEND_TIMED 94 +#define RECEIVEMSG 95 +#define RECEIVE_IF 96 +#define RECEIVE_UNTIL 97 +#define RECEIVE_TIMED 98 +#define RPCMSG 99 +#define RPC_IF 100 +#define RPC_UNTIL 101 +#define RPC_TIMED 102 +#define EVDRP 103 +#define ISRPC 104 +#define RETURNMSG 105 + +// extended intertask messages +#define RPCX 106 +#define RPCX_IF 107 +#define RPCX_UNTIL 108 +#define RPCX_TIMED 109 +#define SENDX 110 +#define SENDX_IF 111 +#define SENDX_UNTIL 112 +#define SENDX_TIMED 113 +#define RETURNX 114 +#define RECEIVEX 115 +#define RECEIVEX_IF 116 +#define RECEIVEX_UNTIL 117 +#define RECEIVEX_TIMED 118 +#define EVDRPX 119 + +// proxies +#define PROXY_ATTACH 120 +#define PROXY_DETACH 121 +#define PROXY_TRIGGER 122 + + +// synchronous user space specific intertask messages and related proxies +#define RT_SEND 123 +#define RT_RECEIVE 124 +#define RT_CRECEIVE 125 +#define RT_REPLY 126 +#define RT_PROXY_ATTACH 127 +#define RT_PROXY_DETACH 128 +#define RT_TRIGGER 129 +#define RT_NAME_ATTACH 130 +#define RT_NAME_DETACH 131 +#define RT_NAME_LOCATE 132 + +// pqueue +#define MQ_OPEN 133 +#define MQ_RECEIVE 134 +#define MQ_SEND 135 +#define MQ_CLOSE 136 +#define MQ_GETATTR 137 +#define MQ_SETATTR 138 +#define MQ_NOTIFY 139 +#define MQ_UNLINK 140 +#define MQ_TIMEDRECEIVE 141 +#define MQ_TIMEDSEND 142 + +// named tasks init/delete +#define NAMED_TASK_INIT 143 +#define NAMED_TASK_INIT_CPUID 144 +#define NAMED_TASK_DELETE 145 + +// registry +#define GET_ADR 146 +#define GET_NAME 147 + +// a semaphore extension +#define COND_SIGNAL 148 + +// new shm +#define SHM_ALLOC 149 +#define SHM_FREE 150 +#define SHM_SIZE 151 +#define HEAP_SET 152 +#define HEAP_ALLOC 153 +#define HEAP_FREE 154 +#define HEAP_NAMED_ALLOC 155 +#define HEAP_NAMED_FREE 156 +#define MALLOC 157 +#define FREE 158 +#define NAMED_MALLOC 159 +#define NAMED_FREE 160 + +#define SUSPEND_IF 161 +#define SUSPEND_UNTIL 162 +#define SUSPEND_TIMED 163 +#define IRQ_WAIT 164 +#define IRQ_WAIT_IF 165 +#define IRQ_WAIT_UNTIL 166 +#define IRQ_WAIT_TIMED 167 +#define IRQ_SIGNAL 168 +#define REQUEST_IRQ_TASK 169 +#define RELEASE_IRQ_TASK 170 +#define SCHED_LOCK 171 +#define SCHED_UNLOCK 172 +#define PEND_LINUX_IRQ 173 +#define SET_LINUX_SYSCALL_MODE 174 +#define REQUEST_RTC 175 +#define RELEASE_RTC 176 +#define RT_GETTID 177 +#define GET_REAL_TIME 178 +#define GET_REAL_TIME_NS 179 + +#define MQ_REG_USP_NOTIFIER 180 + +#define RT_SIGNAL_HELPER 181 +#define RT_SIGNAL_WAITSIG 182 +#define RT_SIGNAL_REQUEST 183 +#define RT_SIGNAL_RELEASE 184 +#define RT_SIGNAL_ENABLE 185 +#define RT_SIGNAL_DISABLE 186 +#define RT_SIGNAL_TRIGGER 187 + +#define SEM_RT_POLL 188 + +#define MAX_LXRT_FUN 189 + +// not recovered yet +// Qblk's +#define RT_INITTICKQUEUE 69 +#define RT_RELEASETICKQUEUE 70 +#define RT_QDYNALLOC 71 +#define RT_QDYNFREE 72 +#define RT_QDYNINIT 73 +#define RT_QBLKWAIT 74 +#define RT_QBLKREPEAT 75 +#define RT_QBLKSOON 76 +#define RT_QBLKDEQUEUE 77 +#define RT_QBLKCANCEL 78 +#define RT_QSYNC 79 +#define RT_QRECEIVE 80 +#define RT_QLOOP 81 +#define RT_QSTEP 82 +#define RT_QBLKBEFORE 83 +#define RT_QBLKAFTER 84 +#define RT_QBLKUNHOOK 85 +#define RT_QBLKRELEASE 86 +#define RT_QBLKCOMPLETE 87 +#define RT_QHOOKFLUSH 88 +#define RT_QBLKATHEAD 89 +#define RT_QBLKATTAIL 90 +#define RT_QHOOKINIT 91 +#define RT_QHOOKRELEASE 92 +#define RT_QBLKSCHEDULE 93 +#define RT_GETTICKQUEUEHOOK 94 +// Testing +#define RT_BOOM 95 +#define RTAI_MALLOC 96 +#define RT_FREE 97 +#define RT_MMGR_STATS 98 +#define RT_STOMP 99 +// VC +#define RT_VC_ATTACH 100 +#define RT_VC_RELEASE 101 +#define RT_VC_RESERVE 102 +// Linux Signal Support +#define RT_GET_LINUX_SIGNAL 103 +#define RT_GET_ERRNO 104 +#define RT_SET_LINUX_SIGNAL_HANDLER 105 +// end of not recovered yet + +#define LXRT_GET_ADR 1000 +#define LXRT_GET_NAME 1001 +#define LXRT_TASK_INIT 1002 +#define LXRT_TASK_DELETE 1003 +#define LXRT_SEM_INIT 1004 +#define LXRT_SEM_DELETE 1005 +#define LXRT_MBX_INIT 1006 +#define LXRT_MBX_DELETE 1007 +#define MAKE_SOFT_RT 1008 +#define MAKE_HARD_RT 1009 +#define PRINT_TO_SCREEN 1010 // free, can be reused +#define NONROOT_HRT 1011 +#define RT_BUDDY 1012 +#define HRT_USE_FPU 1013 +#define USP_SIGHDL 1014 +#define GET_USP_FLAGS 1015 +#define SET_USP_FLAGS 1016 +#define GET_USP_FLG_MSK 1017 +#define SET_USP_FLG_MSK 1018 +#define IS_HARD 1019 +#define LINUX_SERVER 1020 +#define ALLOC_REGISTER 1021 +#define DELETE_DEREGISTER 1022 +#define HARD_SOFT_TOGGLER 1023 +#define PRINTK 1024 +#define GET_EXECTIME 1025 +#define GET_TIMEORIG 1026 +#define LXRT_RWL_INIT 1027 +#define LXRT_RWL_DELETE 1028 +#define LXRT_SPL_INIT 1029 +#define LXRT_SPL_DELETE 1030 +#define SCHED_LATENCIES 1031 +#define GET_CPU_FREQ 1032 + +#define FORCE_SOFT 0x80000000 + +// Keep LXRT call enc/decoding together, so you are sure to act consistently. +// This is the encoding, note " | GT_NR_SYSCALLS" to ensure not a Linux syscall, ... +#define GT_NR_SYSCALLS (1 << 11) +#define ENCODE_LXRT_REQ(dynx, srq, lsize) (((dynx) << 24) | ((srq) << 12) | GT_NR_SYSCALLS | (lsize)) +// ... and this is the decoding. +#define SRQ(x) (((x) >> 12) & 0xFFF) +#define LXRT_NARG(x) ((x) & (GT_NR_SYSCALLS - 1)) +#define INDX(x) (((x) >> 24) & 0xF) + +#define LINUX_SYSCALL_GET_MODE 0 +#define SYNC_LINUX_SYSCALL 1 +#define ASYNC_LINUX_SYSCALL 2 +#define LINUX_SYSCALL_CANCELED 3 +#define LINUX_SYSCALL_GET_CALLBACK ((void *)4) + +#define NSYSCALL_ARGS 7 +#define NSYSCALL_PACARGS 6 + +struct linux_syscall { long args[NSYSCALL_ARGS], mode; void (*cbfun)(long, long); int id; long pacargs[NSYSCALL_PACARGS]; long retval; }; +struct linux_syscalls_list { int in, out, nr, id, mode; void (*cbfun)(long, long); void *serv; struct linux_syscall *syscall; RT_TASK *task; }; + +#ifdef __KERNEL__ + +#include + +/* + Encoding of system call argument + 31 0 +soft SRQ .... |||| |||| |||| .... .... .... .... 0 - 4095 max +int NARG .... .... .... .... |||| |||| |||| |||| +arg INDX |||| .... .... .... .... .... .... .... +*/ + +/* +These USP (unsigned long) type fields allow to readData and write up to 2 arguments. + +The high part of the unsigned long encodes writes +W ARG1 BF .... .... ..|| |... .... .... .... .... +W ARG1 SZ .... ...| ||.. .... .... .... .... .... +W ARG2 BF .... |||. .... .... .... .... .... .... +W ARG2 SZ .||| .... .... .... .... .... .... .... + +The low part of the unsigned long encodes writes +R ARG1 BF .... .... .... .... .... .... ..|| |... +R ARG1 SZ .... .... .... .... .... ...| ||.. .... +R ARG2 BF .... .... .... .... .... |||. .... .... +R ARG2 SZ .... .... .... .... .||| .... .... .... + +The low part of the unsigned long encodes also +RT Switch .... .... .... .... .... .... .... ...| + +If SZ is zero sizeof(int) is copied by default, if LL bit is set sizeof(long long) is copied. +*/ + +// These are for setting appropriate bits in any function entry structure, OR +// them in fun entry type to obtain the desired encoding + +// for writes +#define UW1(bf, sz) ((((bf) & 0x7) << 19) | (((sz) & 0x7) << 22)) +#define UW2(bf, sz) ((((bf) & 0x7) << 25) | (((sz) & 0x7) << 28)) + +// for reads +#define UR1(bf, sz) ((((bf) & 0x7) << 3) | (((sz) & 0x7) << 6)) +#define UR2(bf, sz) ((((bf) & 0x7) << 9) | (((sz) & 0x7) << 12)) + +#define NEED_TO_RW(x) ((x) & 0xFFFFFFFE) + +#define NEED_TO_W(x) ((x) & (0x3F << 19)) +#define NEED_TO_W2ND(x) ((x) & (0x3F << 25)) + +#define NEED_TO_R(x) ((x) & (0x3F << 3)) +#define NEED_TO_R2ND(x) ((x) & (0x3F << 9)) + +#define USP_WBF1(x) (((x) >> 19) & 0x7) +#define USP_WSZ1(x) (((x) >> 22) & 0x7) +#define USP_WBF2(x) (((x) >> 25) & 0x7) +#define USP_WSZ2(x) (((x) >> 28) & 0x7) + +#define USP_RBF1(x) (((x) >> 3) & 0x7) +#define USP_RSZ1(x) (((x) >> 6) & 0x7) +#define USP_RBF2(x) (((x) >> 9) & 0x7) +#define USP_RSZ2(x) (((x) >> 12) & 0x7) + +struct rt_fun_entry { + unsigned long type; + void *fun; +}; + +struct rt_native_fun_entry { + struct rt_fun_entry fun; + int index; +}; + +extern struct rt_fun_entry rt_fun_lxrt[]; + +void reset_rt_fun_entries(struct rt_native_fun_entry *entry); + +int set_rt_fun_entries(struct rt_native_fun_entry *entry); + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*+++++++++++ INLINES FOR PIERRE's PROXIES AND INTERTASK MESSAGES ++++++++++++*/ + +#include +RT_TASK *rt_find_task_by_pid(pid_t); + +static inline struct rt_task_struct *pid2rttask(pid_t pid) +{ + return rt_find_task_by_pid(pid); +} + +static inline long rttask2pid(struct rt_task_struct *task) +{ + return task->tid; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +int set_rtai_callback(void (*fun)(void)); + +void remove_rtai_callback(void (*fun)(void)); + +RT_TASK *rt_lxrt_whoami(void); + +void exec_func(void (*func)(void *data, int evn), + void *data, + int evn); + +int set_rt_fun_ext_index(struct rt_fun_entry *fun, + int idx); + +void reset_rt_fun_ext_index(struct rt_fun_entry *fun, + int idx); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct apic_timer_setup_data; + +#define rt_grow_and_lock_stack(incr) \ + do { \ + char buf[incr]; \ + memset(buf, 0, incr); \ + mlockall(MCL_CURRENT | MCL_FUTURE); \ + } while (0) + +#define BIDX 0 // rt_fun_ext[0] +#define SIZARG sizeof(arg) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Get an object address by its name. + * + * rt_get_adr returns the address associated to @a name. + * + * @return the address associated to @a name on success, 0 on failure + */ +RTAI_PROTO(void *, rt_get_adr, (unsigned long name)) +{ + struct { unsigned long name; } arg = { name }; + return rtai_lxrt(BIDX, SIZARG, LXRT_GET_ADR, &arg).v[LOW]; +} + +/** + * Get an object name by its address. + * + * rt_get_name returns the name pointed by the address @a adr. + * + * @return the identifier pointed by the address @a adr on success, 0 on + * failure. + */ +RTAI_PROTO(unsigned long, rt_get_name, (void *adr)) +{ + struct { void *adr; } arg = { adr }; + return rtai_lxrt(BIDX, SIZARG, LXRT_GET_NAME, &arg).i[LOW]; +} + +#include + +#ifdef CONFIG_RTAI_HARD_SOFT_TOGGLER +#ifndef __SUPPORT_HARD_SOFT_TOGGLER__ +#define __SUPPORT_HARD_SOFT_TOGGLER__ + +static void hard_soft_toggler(int sig) +{ + if (sig == SIGUSR1) { + struct { RT_TASK *task; } arg = { NULL }; + rtai_lxrt(BIDX, SIZARG, HARD_SOFT_TOGGLER, &arg); + } +} + +#endif + +#define SET_SIGNAL_TOGGLER() do { signal(SIGUSR1, hard_soft_toggler); } while(0) + +#else + +#define SET_SIGNAL_TOGGLER() do { } while(0) + +#endif + +RTAI_PROTO(RT_TASK *, rt_task_init_schmod, (unsigned long name, int priority, int stack_size, int max_msg_size, int policy, int cpus_allowed)) +{ + struct sched_param mysched; + struct { unsigned long name; long priority, stack_size, max_msg_size, cpus_allowed; } arg = { name ? name : rt_get_name(NULL), priority, stack_size, max_msg_size, cpus_allowed }; + + SET_SIGNAL_TOGGLER(); + if (policy == SCHED_OTHER) { + mysched.sched_priority = 0; + } else if ((mysched.sched_priority = sched_get_priority_max(policy) - priority) < 1) { + mysched.sched_priority = 1; + } + if (sched_setscheduler(0, policy, &mysched) < 0) { + return 0; + } + rtai_iopl(); + mlockall(MCL_CURRENT | MCL_FUTURE); + + return (RT_TASK *)rtai_lxrt(BIDX, SIZARG, LXRT_TASK_INIT, &arg).v[LOW]; +} + +#define RT_THREAD_STACK_MIN 16*1024 + +#include + +RTAI_PROTO(long, rt_thread_create, (void *fun, void *args, int stack_size)) +{ + long thread; + pthread_attr_t attr; + + pthread_attr_init(&attr); + if (!pthread_attr_setstacksize(&attr, stack_size > RT_THREAD_STACK_MIN ? stack_size : RT_THREAD_STACK_MIN)) { + struct { unsigned long hs; } arg = { 0 }; + if ((arg.hs = rtai_lxrt(BIDX, SIZARG, IS_HARD, &arg).i[LOW])) { + rtai_lxrt(BIDX, SIZARG, MAKE_SOFT_RT, &arg); + } + if (pthread_create((pthread_t *)&thread, &attr, (void *(*)(void *))fun, args)) { + thread = 0; + } + if (arg.hs) { + rtai_lxrt(BIDX, SIZARG, MAKE_HARD_RT, &arg); + } + } else { + thread = 0; + } + return thread; +} + +RTAI_PROTO(int, rt_thread_join, (long thread)) +{ + return pthread_join((pthread_t)thread, NULL); +} + +#ifndef __SUPPORT_LINUX_SERVER__ +#define __SUPPORT_LINUX_SERVER__ + +#include +#include + +static void linux_syscall_server_fun(struct linux_syscalls_list *list) +{ + struct linux_syscalls_list syscalls; + + syscalls = *list; + syscalls.serv = &syscalls; + if ((syscalls.serv = rtai_lxrt(BIDX, sizeof(struct linux_syscalls_list), LINUX_SERVER, &syscalls).v[LOW])) { + long *args; + struct linux_syscall *todo; + struct linux_syscall calldata[syscalls.nr]; + syscalls.syscall = calldata; + memset(calldata, 0, sizeof(calldata)); + mlockall(MCL_CURRENT | MCL_FUTURE); + list->serv = &syscalls; + rtai_lxrt(BIDX, sizeof(RT_TASK *), RESUME, &syscalls.task); + while (abs(rtai_lxrt(BIDX, sizeof(RT_TASK *), SUSPEND, &syscalls.serv).i[LOW]) < RTE_LOWERR) { + if (syscalls.syscall[syscalls.out].mode != LINUX_SYSCALL_CANCELED) { + todo = &syscalls.syscall[syscalls.out]; + args = todo->args; + todo->retval = syscall(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + todo->id = -todo->id; + if (todo->mode == SYNC_LINUX_SYSCALL) { + rtai_lxrt(BIDX, sizeof(RT_TASK *), RESUME, &syscalls.task); + } else if (syscalls.cbfun) { + todo->cbfun(args[0], todo->retval); + } + } + if (++syscalls.out >= syscalls.nr) { + syscalls.out = 0; + } + } + } + rtai_lxrt(BIDX, sizeof(RT_TASK *), LXRT_TASK_DELETE, &syscalls.serv); +} + +#endif /* __SUPPORT_LINUX_SERVER__ */ + +RTAI_PROTO(int, rt_set_linux_syscall_mode, (int mode, void (*cbfun)(long, long))) +{ + struct { long mode; void (*cbfun)(long, long); } arg = { mode, cbfun }; + return rtai_lxrt(BIDX, SIZARG, SET_LINUX_SYSCALL_MODE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_linux_syscall_mode, (struct linux_syscalls_list *syscalls, int mode)) +{ + int retval; + if (syscalls == NULL) { + return EINVAL; + } + retval = syscalls->mode; + if (mode == SYNC_LINUX_SYSCALL || mode == ASYNC_LINUX_SYSCALL) { + syscalls->mode = mode; + } + return retval; +} + +RTAI_PROTO(void *, rt_linux_syscall_cbfun, (struct linux_syscalls_list *syscalls, void (*cbfun)(long, long))) +{ + void *retval; + if (syscalls == NULL) { + return (void *)EINVAL; + } + retval = (void *)((unsigned long)syscalls->cbfun); + if ((unsigned long)cbfun > (unsigned long)LINUX_SYSCALL_GET_CALLBACK) { + syscalls->cbfun = cbfun; + } + return retval; +} + +RTAI_PROTO(int, rt_linux_syscall_status, (struct linux_syscalls_list *syscalls, int id, int *retval)) +{ + int slot, slotid; + if (syscalls == NULL || id < 0) { + return EINVAL; + } + if (id != abs(slotid = syscalls->syscall[slot = id%syscalls->nr].id)) { + return ENOENT; + } + if (syscalls->syscall[slot].mode == LINUX_SYSCALL_CANCELED) { + return ECANCELED; + } + if (slotid > 0) { + return EINPROGRESS; + } + if (retval) { + *retval = syscalls->syscall[slot].retval; + } + return 0; +} + +RTAI_PROTO(int, rt_linux_syscall_cancel, (struct linux_syscalls_list *syscalls, int id)) +{ + int slot, slotid; + if (syscalls == NULL || id < 0) { + return EINVAL; + } + if (id != abs(slotid = syscalls->syscall[slot = id%syscalls->nr].id)) { + return ENOENT; + } + if (slotid < 0) { + return slotid; + } + syscalls->syscall[slot].mode = LINUX_SYSCALL_CANCELED; + return 0; +} + +RTAI_PROTO(void *, rt_create_linux_syscall_server, (RT_TASK *task, int mode, void (*cbfun)(long, long), int nr_bufd_async_calls)) +{ + if ((task || (task = (RT_TASK *)rtai_lxrt(BIDX, sizeof(RT_TASK *), RT_BUDDY, &task).v[LOW])) && nr_bufd_async_calls > 0) { + struct linux_syscalls_list syscalls; + memset(&syscalls, 0, sizeof(syscalls)); + syscalls.task = task; + syscalls.cbfun = cbfun; + syscalls.nr = nr_bufd_async_calls + 1; + syscalls.mode = mode; + syscalls.serv = NULL; + if (rt_thread_create((void *)linux_syscall_server_fun, &syscalls, RT_THREAD_STACK_MIN + syscalls.nr*sizeof(struct linux_syscall))) { + rtai_lxrt(BIDX, sizeof(RT_TASK *), SUSPEND, &task); + return syscalls.serv; + } + } + return NULL; +} + +#define rt_sync_async_linux_syscall_server_create(task, mode, cbfun, nr_calls) rt_create_linux_syscall_server(task, mode, cbfun, nr_calls) + +#define rt_linux_syscall_server_create(task) rt_sync_async_linux_syscall_server_create(task, SYNC_LINUX_SYSCALL, NULL, 1); + +RTAI_PROTO(void, rt_destroy_linux_syscall_server, (RT_TASK *task)) +{ + struct linux_syscalls_list s; + s.nr = 0; + s.task = task; + rtai_lxrt(BIDX, sizeof(struct linux_syscalls_list), LINUX_SERVER, &s); +} + +RTAI_PROTO(RT_TASK *, rt_thread_init, (unsigned long name, int priority, int max_msg_size, int policy, int cpus_allowed)) +{ + return rt_task_init_schmod(name, priority, 0, max_msg_size, policy, cpus_allowed); +} + +/** + * Create an RTAI task extension for a Linux process/task in user space. + * + * rt_task_init extends the Linux task structure, making it possible to use + * RTAI APIs that wants to access RTAI scheduler services. It needs no task + * function as none is used, but it does need to setup an RTAI task structure + * and initialize it appropriately as the provided services are carried out as + * if the Linux process has become an RTAI task also. Because of that it + * requires less arguments and returns the pointer to the RTAI task extension + * that is to be used in related calls. + * + * @param name is a unique identifier that is possibly used to ease + * referencing the RTAI task extension of a peer Linux process. + * + * @param priority is the priority of the RTAI task extension. + * + * @param stack_size, a legacy parameter used nomore; kept for portability + * reasons only. (It was just what is implied by such a name and referred to + * the stack size used by the buddy in the very first implementation of LXRT). + * + * @param max_msg_size is a hint for the size of the most lengthy intertask + * message that is likely to be exchanged. + * + * @a max_msg_size can be zero, in which case a default internal value is + * used. Keep an eye on such a default message (256) size. It could be + * possible that a larger size is required to suite your needs best. In such + * a case either recompile sys.c with the macro MSG_SIZE set appropriately, + * or assign a larger size here esplicitly. Note that the message size is + * not critical though. In fact the module reassigns it, dynamically and + * appropriately sized, whenever it is needed. The cost is a real time + * allocation of the new buffer. + * Note also that @a max_msg_size is for a buffer to be used to copy whatever + * intertask message from user to kernel space, as intertask messages are not + * necessarily used immediately. + * + * It is important to remark that the returned task pointers cannot be used + * directly, they are for kernel space data, but just passed as arguments when + * needed. + * + * @return On success a pointer to the task structure initialized in kernel + * space. + * @return On failure a NULL value is returned if it was not possible to setup + * the RTAI task extension or something using the same name was found. + */ +RTAI_PROTO(RT_TASK *,rt_task_init,(unsigned long name, int priority, int stack_size, int max_msg_size)) +{ + (void)stack_size; + return rt_task_init_schmod(name, priority, 0, max_msg_size, SCHED_FIFO, 0xFF); +} + +RTAI_PROTO(void,rt_set_sched_policy,(RT_TASK *task, int policy, int rr_quantum_ns)) +{ + struct { RT_TASK *task; long policy; long rr_quantum_ns; } arg = { task, policy, rr_quantum_ns }; + rtai_lxrt(BIDX, SIZARG, SET_SCHED_POLICY, &arg); +} + +RTAI_PROTO(int,rt_change_prio,(RT_TASK *task, int priority)) +{ + struct { RT_TASK *task; long priority; } arg = { task, priority }; + return rtai_lxrt(BIDX, SIZARG, CHANGE_TASK_PRIO, &arg).i[LOW]; +} + +/** + * Return a hard real time Linux process, or pthread to the standard Linux + * behavior. + * + * rt_make_soft_real_time returns to soft Linux POSIX real time a process, from + * which it is called, that was made hard real time by a call to + * rt_make_hard_real_time. + * + * Only the process itself can use this functions, it is not possible to impose + * the related transition from another process. + * + */ +RTAI_PROTO(void, rt_make_soft_real_time, (void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, MAKE_SOFT_RT, &arg); +} + +RTAI_PROTO(int, rt_thread_delete,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + rt_make_soft_real_time(); + return rtai_lxrt(BIDX, SIZARG, LXRT_TASK_DELETE, &arg).i[LOW]; +} + +#define rt_task_delete(task) rt_thread_delete(task) + +RTAI_PROTO(int,rt_task_yield,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, YIELD, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_suspend,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, SUSPEND, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_suspend_if,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, SUSPEND_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_suspend_until,(RT_TASK *task, RTIME time)) +{ + struct { RT_TASK *task; RTIME time; } arg = { task, time }; + return rtai_lxrt(BIDX, SIZARG, SUSPEND_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_suspend_timed,(RT_TASK *task, RTIME delay)) +{ + struct { RT_TASK *task; RTIME delay; } arg = { task, delay }; + return rtai_lxrt(BIDX, SIZARG, SUSPEND_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_resume,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, RESUME, &arg).i[LOW]; +} + +RTAI_PROTO(void, rt_sched_lock, (void)) +{ + struct { long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, SCHED_LOCK, &arg); +} + +RTAI_PROTO(void, rt_sched_unlock, (void)) +{ + struct { long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, SCHED_UNLOCK, &arg); +} + +RTAI_PROTO(void, rt_pend_linux_irq, (unsigned irq)) +{ + struct { unsigned long irq; } arg = { irq }; + rtai_lxrt(BIDX, SIZARG, PEND_LINUX_IRQ, &arg); +} + +RTAI_PROTO(int, rt_irq_wait, (unsigned irq)) +{ + struct { unsigned long irq; } arg = { irq }; + return rtai_lxrt(BIDX, SIZARG, IRQ_WAIT, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_irq_wait_if, (unsigned irq)) +{ + struct { unsigned long irq; } arg = { irq }; + return rtai_lxrt(BIDX, SIZARG, IRQ_WAIT_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_irq_wait_until, (unsigned irq, RTIME time)) +{ + struct { unsigned long irq; RTIME time; } arg = { irq, time }; + return rtai_lxrt(BIDX, SIZARG, IRQ_WAIT_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_irq_wait_timed, (unsigned irq, RTIME delay)) +{ + struct { unsigned long irq; RTIME delay; } arg = { irq, delay }; + return rtai_lxrt(BIDX, SIZARG, IRQ_WAIT_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_irq_signal, (unsigned irq)) +{ + struct { unsigned long irq; } arg = { irq }; + return rtai_lxrt(BIDX, SIZARG, IRQ_SIGNAL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_request_irq_task, (unsigned irq, void *handler, int type, int affine2task)) +{ + struct { unsigned long irq; void *handler; long type, affine2task; } arg = { irq, handler, type, affine2task }; + return rtai_lxrt(BIDX, SIZARG, REQUEST_IRQ_TASK, &arg).i[LOW]; +} + + +RTAI_PROTO(int, rt_release_irq_task, (unsigned irq)) +{ + struct { unsigned long irq; } arg = { irq }; + return rtai_lxrt(BIDX, SIZARG, RELEASE_IRQ_TASK, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_task_make_periodic,(RT_TASK *task, RTIME start_time, RTIME period)) +{ + struct { RT_TASK *task; RTIME start_time, period; } arg = { task, start_time, period }; + return rtai_lxrt(BIDX, SIZARG, MAKE_PERIODIC, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_make_periodic_relative_ns,(RT_TASK *task, RTIME start_delay, RTIME period)) +{ + struct { RT_TASK *task; RTIME start_time, period; } arg = { task, start_delay, period }; + return rtai_lxrt(BIDX, SIZARG, MAKE_PERIODIC_NS, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_wait_period,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, WAIT_PERIOD, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_sleep,(RTIME delay)) +{ + struct { RTIME delay; } arg = { delay }; + return rtai_lxrt(BIDX, SIZARG, SLEEP, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_sleep_until,(RTIME time)) +{ + struct { RTIME time; } arg = { time }; + return rtai_lxrt(BIDX, SIZARG, SLEEP_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_is_hard_timer_running,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, HARD_TIMER_RUNNING, &arg).i[LOW]; +} + +RTAI_PROTO(RTIME, start_rt_timer, (int period)) +{ + int hs; + RTIME retval; + struct { long period; } arg = { 0 }; + if ((hs = rtai_lxrt(BIDX, SIZARG, IS_HARD, &arg).i[LOW])) { + rtai_lxrt(BIDX, SIZARG, MAKE_SOFT_RT, &arg); + } + arg.period = period; + retval = rtai_lxrt(BIDX, SIZARG, START_TIMER, &arg).rt; + if (hs) { + rtai_lxrt(BIDX, SIZARG, MAKE_HARD_RT, &arg); + } + return retval; +} + +RTAI_PROTO(void, stop_rt_timer, (void)) +{ + struct { long hs; } arg = { 0 }; + if ((arg.hs = rtai_lxrt(BIDX, SIZARG, IS_HARD, &arg).i[LOW])) { + rtai_lxrt(BIDX, SIZARG, MAKE_SOFT_RT, &arg); + } + rtai_lxrt(BIDX, SIZARG, STOP_TIMER, &arg); + if (arg.hs) { + rtai_lxrt(BIDX, SIZARG, MAKE_HARD_RT, &arg); + } +} + +RTAI_PROTO(void, rt_request_rtc, (int rtc_freq, void *handler)) +{ + struct { long rtc_freq; void *handler; } arg = { rtc_freq, handler }; + rtai_lxrt(BIDX, SIZARG, REQUEST_RTC, &arg); +} + +RTAI_PROTO(void, rt_release_rtc, (void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, RELEASE_RTC, &arg); +} + +RTAI_PROTO(RTIME, rt_get_time, (void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_TIME, &arg).rt; +} + +RTAI_PROTO(RTIME, rt_get_real_time, (void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_REAL_TIME, &arg).rt; +} + +RTAI_PROTO(RTIME, rt_get_real_time_ns, (void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_REAL_TIME_NS, &arg).rt; +} + +RTAI_PROTO(RTIME, count2nano, (RTIME count)) +{ + struct { RTIME count; } arg = { count }; + return rtai_lxrt(BIDX, SIZARG, COUNT2NANO, &arg).rt; +} + +RTAI_PROTO(RTIME, nano2count, (RTIME nanos)) +{ + struct { RTIME nanos; } arg = { nanos }; + return rtai_lxrt(BIDX, SIZARG, NANO2COUNT, &arg).rt; +} + +RTAI_PROTO(void, rt_busy_sleep, (int ns)) +{ + struct { long ns; } arg = { ns }; + rtai_lxrt(BIDX, SIZARG, BUSY_SLEEP, &arg); +} + +RTAI_PROTO(void, rt_set_periodic_mode, (void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, SET_PERIODIC_MODE, &arg); +} + +RTAI_PROTO(void, rt_set_oneshot_mode, (void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, SET_ONESHOT_MODE, &arg); +} + +RTAI_PROTO(int, rt_task_signal_handler, (RT_TASK *task, void (*handler)(void))) +{ + struct { RT_TASK *task; void (*handler)(void); } arg = { task, handler }; + return rtai_lxrt(BIDX, SIZARG, SIGNAL_HANDLER, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_task_use_fpu,(RT_TASK *task, int use_fpu_flag)) +{ + struct { RT_TASK *task; long use_fpu_flag; } arg = { task, use_fpu_flag }; + if (rtai_lxrt(BIDX, SIZARG, RT_BUDDY, &arg).v[LOW] != task) { + return rtai_lxrt(BIDX, SIZARG, TASK_USE_FPU, &arg).i[LOW]; + } else { +// note that it would be enough to do whatever FP op here to have it OK. But +// that is scary if it is done when already in hard real time, and we do not +// want to force users to call this before making it hard. + rtai_lxrt(BIDX, SIZARG, HRT_USE_FPU, &arg); + return 0; + } +} + +RTAI_PROTO(int,rt_buddy_task_use_fpu,(RT_TASK *task, int use_fpu_flag)) +{ + struct { RT_TASK *task; long use_fpu_flag; } arg = { task, use_fpu_flag }; + return rtai_lxrt(BIDX, SIZARG, TASK_USE_FPU, &arg).i[LOW]; +} + +/* +RTAI_PROTO(int,rt_linux_use_fpu,(int use_fpu_flag)) +{ + struct { long use_fpu_flag; } arg = { use_fpu_flag }; + return rtai_lxrt(BIDX, SIZARG, LINUX_USE_FPU, &arg).i[LOW]; +} +*/ + +RTAI_PROTO(int, rt_task_get_info, (RT_TASK *task, RT_TASK_INFO *task_info)) +{ + struct { RT_TASK *task; RT_TASK_INFO *taskinfo; } arg = { task, task_info }; + if (task_info && !rtai_lxrt(BIDX, SIZARG, GET_TASK_INFO, &arg).i[LOW]) { + return 0; + } + return -EINVAL; +} + +RTAI_PROTO(int, rt_get_priorities, (RT_TASK *task, int *priority, int *base_priority)) +{ + RT_TASK_INFO task_info; + if (priority && base_priority && !rt_task_get_info(task, &task_info)) { + *priority = task_info.priority; + *base_priority = task_info.base_priority; + return 0; + } + return -EINVAL; +} + +RTAI_PROTO(int, rt_hard_timer_tick, (void)) +{ + struct { long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, HARD_TIMER_COUNT, &arg).i[LOW]; +} + +RTAI_PROTO(RTIME,rt_get_time_ns,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_TIME_NS, &arg).rt; +} + +RTAI_PROTO(RTIME,rt_get_cpu_time_ns,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_CPU_TIME_NS, &arg).rt; +} + +#define rt_named_task_init(task_name, thread, data, stack_size, prio, uses_fpu, signal) \ + rt_task_init(nam2num(task_name), thread, data, stack_size, prio, uses_fpu, signal) + +#define rt_named_task_init_cpuid(task_name, thread, data, stack_size, prio, uses_fpu, signal, run_on_cpu) \ + rt_task_init_cpuid(nam2num(task_name), thread, data, stack_size, prio, uses_fpu, signal, run_on_cpu) + +RTAI_PROTO(void,rt_set_runnable_on_cpus,(RT_TASK *task, unsigned long cpu_mask)) +{ + struct { RT_TASK *task; unsigned long cpu_mask; } arg = { task, cpu_mask }; + rtai_lxrt(BIDX, SIZARG, SET_RUNNABLE_ON_CPUS, &arg); +} + +RTAI_PROTO(void,rt_set_runnable_on_cpuid,(RT_TASK *task, unsigned int cpuid)) +{ + struct { RT_TASK *task; unsigned long cpuid; } arg = { task, cpuid }; + rtai_lxrt(BIDX, SIZARG, SET_RUNNABLE_ON_CPUID, &arg); +} + +RTAI_PROTO(int,rt_get_timer_cpu,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_TIMER_CPU, &arg).i[LOW]; +} + +RTAI_PROTO(void,start_rt_apic_timers,(struct apic_timer_setup_data *setup_mode, unsigned int rcvr_jiffies_cpuid)) +{ + struct { struct apic_timer_setup_data *setup_mode; unsigned long rcvr_jiffies_cpuid; } arg = { setup_mode, rcvr_jiffies_cpuid }; + rtai_lxrt(BIDX, SIZARG, START_RT_APIC_TIMERS, &arg); +} + +RTAI_PROTO(int, rt_hard_timer_tick_cpuid, (int cpuid)) +{ + struct { long cpuid; } arg = { cpuid }; + return rtai_lxrt(BIDX, SIZARG, HARD_TIMER_COUNT_CPUID, &arg).i[LOW]; +} + +RTAI_PROTO(RTIME,count2nano_cpuid,(RTIME count, unsigned int cpuid)) +{ + struct { RTIME count; unsigned long cpuid; } arg = { count, cpuid }; + return rtai_lxrt(BIDX, SIZARG, COUNT2NANO_CPUID, &arg).rt; +} + +RTAI_PROTO(RTIME,nano2count_cpuid,(RTIME nanos, unsigned int cpuid)) +{ + struct { RTIME nanos; unsigned long cpuid; } arg = { nanos, cpuid }; + return rtai_lxrt(BIDX, SIZARG, NANO2COUNT_CPUID, &arg).rt; +} + +RTAI_PROTO(RTIME,rt_get_time_cpuid,(unsigned int cpuid)) +{ + struct { unsigned long cpuid; } arg = { cpuid }; + return rtai_lxrt(BIDX, SIZARG, GET_TIME_CPUID, &arg).rt; +} + +RTAI_PROTO(RTIME,rt_get_time_ns_cpuid,(unsigned int cpuid)) +{ + struct { unsigned long cpuid; } arg = { cpuid }; + return rtai_lxrt(BIDX, SIZARG, GET_TIME_NS_CPUID, &arg).rt; +} + +RTAI_PROTO(void,rt_boom,(void)) +{ + struct { long dummy; } arg = { 0 }; + rtai_lxrt(BIDX, SIZARG, RT_BOOM, &arg); +} + +RTAI_PROTO(void,rt_mmgr_stats,(void)) +{ + struct { long dummy; } arg = { 0 }; + rtai_lxrt(BIDX, SIZARG, RT_MMGR_STATS, &arg); +} + +RTAI_PROTO(void,rt_stomp,(void) ) +{ + struct { long dummy; } arg = { 0 }; + rtai_lxrt(BIDX, SIZARG, RT_STOMP, &arg); +} + +RTAI_PROTO(int,rt_get_linux_signal,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, RT_GET_LINUX_SIGNAL, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_get_errno,(RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, RT_GET_ERRNO, &arg).i[LOW]; +} + +RTAI_PROTO(int,rt_set_linux_signal_handler,(RT_TASK *task, void (*handler)(int sig))) +{ + struct { RT_TASK *task; void (*handler)(int sig); } arg = { task, handler }; + return rtai_lxrt(BIDX, SIZARG, RT_SET_LINUX_SIGNAL_HANDLER, &arg).i[LOW]; +} + +#define VSNPRINTF_BUF_SIZE 256 +RTAI_PROTO(int,rt_printk,(const char *format, ...)) +{ + char display[VSNPRINTF_BUF_SIZE]; + struct { const char *display; long nch; } arg = { display, 0 }; + va_list args; + + va_start(args, format); + arg.nch = vsnprintf(display, VSNPRINTF_BUF_SIZE, format, args); + va_end(args); + rtai_lxrt(BIDX, SIZARG, PRINTK, &arg); + return arg.nch; +} + +RTAI_PROTO(int,rtai_print_to_screen,(const char *format, ...)) +{ + char display[VSNPRINTF_BUF_SIZE]; + struct { const char *display; long nch; } arg = { display, 0 }; + va_list args; + + va_start(args, format); + arg.nch = vsnprintf(display, VSNPRINTF_BUF_SIZE, format, args); + va_end(args); + rtai_lxrt(BIDX, SIZARG, PRINTK, &arg); + return arg.nch; +} + +RTAI_PROTO(int,rt_usp_signal_handler,(void (*handler)(void))) +{ + struct { void (*handler)(void); } arg = { handler }; + return rtai_lxrt(BIDX, SIZARG, USP_SIGHDL, &arg).i[0]; +} + +RTAI_PROTO(unsigned long,rt_get_usp_flags,(RT_TASK *rt_task)) +{ + struct { RT_TASK *task; } arg = { rt_task }; + return rtai_lxrt(BIDX, SIZARG, GET_USP_FLAGS, &arg).i[LOW]; +} + +RTAI_PROTO(unsigned long,rt_get_usp_flags_mask,(RT_TASK *rt_task)) +{ + struct { RT_TASK *task; } arg = { rt_task }; + return rtai_lxrt(BIDX, SIZARG, GET_USP_FLG_MSK, &arg).i[LOW]; +} + +RTAI_PROTO(void,rt_set_usp_flags,(RT_TASK *rt_task, unsigned long flags)) +{ + struct { RT_TASK *task; unsigned long flags; } arg = { rt_task, flags }; + rtai_lxrt(BIDX, SIZARG, SET_USP_FLAGS, &arg); +} + +RTAI_PROTO(void,rt_set_usp_flags_mask,(unsigned long flags_mask)) +{ + struct { unsigned long flags_mask; } arg = { flags_mask }; + rtai_lxrt(BIDX, SIZARG, SET_USP_FLG_MSK, &arg); +} + +RTAI_PROTO(pid_t, rt_get_linux_tid, (RT_TASK *task)) +{ + struct { RT_TASK *task; } arg = { task }; + return rtai_lxrt(BIDX, SIZARG, HARD_SOFT_TOGGLER, &arg).i[LOW]; +} + +RTAI_PROTO(RT_TASK *,rt_agent,(void)) +{ + struct { unsigned long dummy; } arg; + return (RT_TASK *)rtai_lxrt(BIDX, SIZARG, RT_BUDDY, &arg).v[LOW]; +} + +#define rt_buddy() rt_agent() + +RTAI_PROTO(int, rt_gettid, (void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, RT_GETTID, &arg).i[LOW]; +} + +/** + * Give a Linux process, or pthread, hard real time execution capabilities + * allowing full kernel preemption. + * + * rt_make_hard_real_time makes the soft Linux POSIX real time process, from + * which it is called, a hard real time LXRT process. It is important to + * remark that this function must be used only with soft Linux POSIX processes + * having their memory locked in memory. See Linux man pages. + * + * Only the process itself can use this functions, it is not possible to impose + * the related transition from another process. + * + * Note that processes made hard real time should avoid making any Linux System + * call that can lead to a task switch as Linux cannot run anymore processes + * that are made hard real time. To interact with Linux you should couple the + * process that was made hard real time with a Linux buddy server, either + * standard or POSIX soft real time. To communicate and synchronize with the + * buddy you can use the wealth of available RTAI, and its schedulers, services. + * + * After all it is pure nonsense to use a non hard real time Operating System, + * i.e. Linux, from within hard real time processes. + */ +RTAI_PROTO(void,rt_make_hard_real_time,(void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, MAKE_HARD_RT, &arg); +} + +/** + * Allows a non root user to use the Linux POSIX soft real time process + * management and memory lock functions, and allows it to do any input-output + * operation from user space. + * + * Only the process itself can use this functions, it is not possible to impose + * the related transition from another process. + */ +RTAI_PROTO(void,rt_allow_nonroot_hrt,(void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, NONROOT_HRT, &arg); +} + +RTAI_PROTO(int,rt_is_hard_real_time,(RT_TASK *rt_task)) +{ + struct { RT_TASK *task; } arg = { rt_task }; + return rtai_lxrt(BIDX, SIZARG, IS_HARD, &arg).i[LOW]; +} + +#define rt_is_soft_real_time(rt_task) (!rt_is_hard_real_time((rt_task))) + +RTAI_PROTO(void,rt_task_set_resume_end_times,(RTIME resume, RTIME end)) +{ + struct { RTIME resume, end; } arg = { resume, end }; + rtai_lxrt(BIDX, SIZARG, SET_RESUME_END, &arg); +} + +RTAI_PROTO(int,rt_set_resume_time,(RT_TASK *rt_task, RTIME new_resume_time)) +{ + struct { RT_TASK *rt_task; RTIME new_resume_time; } arg = { rt_task, new_resume_time }; + return rtai_lxrt(BIDX, SIZARG, SET_RESUME_TIME, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_set_period, (RT_TASK *rt_task, RTIME new_period)) +{ + struct { RT_TASK *rt_task; RTIME new_period; } arg = { rt_task, new_period }; + return rtai_lxrt(BIDX, SIZARG, SET_PERIOD, &arg).i[LOW]; +} + +RTAI_PROTO(void, rt_spv_RMS, (int cpuid)) +{ + struct { long cpuid; } arg = { cpuid }; + rtai_lxrt(BIDX, SIZARG, SPV_RMS, &arg); +} + +RTAI_PROTO(int, rt_task_masked_unblock, (RT_TASK *task, unsigned long mask)) +{ + struct { RT_TASK *task; unsigned long mask; } arg = { task, mask }; + return rtai_lxrt(BIDX, SIZARG, WAKEUP_SLEEPING, &arg).i[LOW]; +} + +#define rt_task_wakeup_sleeping(task) rt_task_masked_unblock(task, RT_SCHED_DELAYED) + +RTAI_PROTO(void, rt_get_exectime, (RT_TASK *task, RTIME *exectime)) +{ + struct { RT_TASK *task; RTIME *exectime; } arg = { task, exectime }; + rtai_lxrt(BIDX, SIZARG, GET_EXECTIME, &arg); +} + +RTAI_PROTO(void, rt_gettimeorig, (RTIME time_orig[])) +{ + struct { RTIME *time_orig; } arg = { time_orig }; + rtai_lxrt(BIDX, SIZARG, GET_TIMEORIG, &arg); +} + +RTAI_PROTO(RT_TASK *,ftask_init,(unsigned long name, int priority)) +{ + struct { unsigned long name; long priority, stack_size, max_msg_size, cpus_allowed; } arg = { name, priority, 0, 0, 0 }; + return (RT_TASK *)rtai_lxrt(BIDX, SIZARG, LXRT_TASK_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(RTIME, start_ftimer,(long period, long ftick_freq)) +{ + struct { long ftick_freq; void *handler; } arg = { ftick_freq, NULL }; + if (!period) { + rtai_lxrt(BIDX, sizeof(long), SET_ONESHOT_MODE, &period); + } else { + rtai_lxrt(BIDX, sizeof(long), SET_PERIODIC_MODE, &period); + } + rtai_lxrt(BIDX, SIZARG, REQUEST_RTC, &arg); + return rtai_lxrt(BIDX, sizeof(long), START_TIMER, &period).rt; +} + +RTAI_PROTO(RTIME, stop_ftimer,(void)) +{ + struct { long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, RELEASE_RTC, &arg); + return rtai_lxrt(BIDX, SIZARG, STOP_TIMER, &arg).rt; +} + +RTAI_PROTO(int, rt_sched_latencies, (int klat, int ulat, int period)) +{ + struct { long period, loops, Latency; } arg = { klat, ulat, period }; + return rtai_lxrt(BIDX, SIZARG, SCHED_LATENCIES, &arg).i[0]; +} + +RTAI_PROTO(unsigned int, rt_get_cpu_freq, (void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, GET_CPU_FREQ, &arg).i[0]; +} + +static inline RTIME nanos2tscnts(RTIME nanos, unsigned int cpu_freq) +{ + return (RTIME)((long double)nanos*((long double)cpu_freq/(long double)1000000000)); +} + +static inline RTIME tscnts2nanos(RTIME tscnts, unsigned int cpu_freq) +{ + return (RTIME)((long double)tscnts*((long double)1000000000/(long double)cpu_freq)); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +/*@}*/ + +#endif /* !_RTAI_LXRT_H */ diff --git a/include/rtai_malloc.h b/include/rtai_malloc.h new file mode 100644 index 0000000..b3b7251 --- /dev/null +++ b/include/rtai_malloc.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2001,2002,2003,2004 Philippe Gerum . + * + * 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, see . + * + * This file provides the interface to the RTAI dynamic memory + * allocator based on the algorithm described in "Design of a General + * Purpose Memory Allocator for the 4.3BSD Unix Kernel" by Marshall + * K. McKusick and Michael J. Karels. + */ + +#ifndef _RTAI_MALLOC_H +#define _RTAI_MALLOC_H + +#include + +#ifdef __KERNEL__ + +#ifndef __cplusplus + +#include +#include +#include + +/* + * LIMITS: + * + * Minimum page size is 2 ** RTHEAP_MINLOG2 (must be large enough to + * hold a pointer). + * + * Maximum page size is 2 ** RTHEAP_MAXLOG2. + * + * Minimum block size equals the minimum page size. + * + * Requested block size smaller than the minimum block size is + * rounded to the minimum block size. + * + * Requested block size larger than 2 times the page size is rounded + * to the next page boundary and obtained from the free page + * list. So we need a bucket for each power of two between + * RTHEAP_MINLOG2 and RTHEAP_MAXLOG2 inclusive, plus one to honor + * requests ranging from the maximum page size to twice this size. + */ + +#define RTHEAP_MINLOG2 4 +#define RTHEAP_MAXLOG2 22 +#define RTHEAP_MINALLOCSZ (1 << RTHEAP_MINLOG2) +#define RTHEAP_MINALIGNSZ RTHEAP_MINALLOCSZ +#define RTHEAP_NBUCKETS (RTHEAP_MAXLOG2 - RTHEAP_MINLOG2 + 2) +#define RTHEAP_MAXEXTSZ 0x7FFFFFFF +#define RTHEAP_GLOBALSZ (CONFIG_RTAI_MALLOC_HEAPSZ * 1024) + +#define RTHEAP_PFREE 0 +#define RTHEAP_PCONT 1 +#define RTHEAP_PLIST 2 + +#define KMALLOC_LIMIT (128 * 1024) + +#define RTHEAP_NOMEM (-1) +#define RTHEAP_PARAM (-2) + +typedef struct rtextent { + + struct list_head link; + + caddr_t membase, /* Base address of the page array */ + memlim, /* Memory limit of page array */ + freelist; /* Head of the free page list */ + + u_char pagemap[1]; /* Beginning of page map */ + +} rtextent_t; + +/* Creation flag */ +#define RTHEAP_EXTENDABLE 0x1 + +/* Allocation flags */ +#define RTHEAP_EXTEND 0x1 + +typedef struct rtheap { + + spinlock_t lock; + + int flags; + + u_long extentsize, + pagesize, + pageshift, + hdrsize, + npages, /* Number of pages per extent */ + ubytes, + maxcont; + + struct list_head extents; + + caddr_t buckets[RTHEAP_NBUCKETS]; + +} rtheap_t; + +#else /* __cplusplus */ + +struct rtheap; + +typedef struct rtheap rtheap_t; + +#endif /* !__cplusplus */ + +extern rtheap_t rtai_global_heap; + +#define rtheap_page_size(heap) ((heap)->pagesize) +#define rtheap_page_count(heap) ((heap)->npages) +#define rtheap_used_mem(heap) ((heap)->ubytes) + +#ifdef CONFIG_RTAI_MALLOC +#define rt_malloc(sz) rtheap_alloc(&rtai_global_heap, sz, 0) +#define rt_free(p) rtheap_free(&rtai_global_heap, p) +#else +#define rt_malloc(sz) kmalloc(sz, GFP_KERNEL) +#define rt_free(p) kfree(p) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int __rtai_heap_init(void); + +void __rtai_heap_exit(void); + +int rtheap_init(rtheap_t *heap, void *heapaddr, u_long heapsize, u_long pagesize, int suprt); + +void rtheap_destroy(rtheap_t *heap, int suprt); + +void *rtheap_alloc(rtheap_t *heap, u_long size, int flags); + +int rtheap_free(rtheap_t *heap, void *block); + +#ifdef __cplusplus +} +#endif + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_MALLOC_H */ diff --git a/include/rtai_mbx.h b/include/rtai_mbx.h new file mode 100644 index 0000000..798fb3c --- /dev/null +++ b/include/rtai_mbx.h @@ -0,0 +1,288 @@ +/** + * @ingroup lxrt + * @file + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999-2003 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_MBX_H +#define _RTAI_MBX_H + +#include + +#define RT_MBX_MAGIC 0x3f81aab // nam2num("rtmbx") + +struct rt_task_struct; +struct rt_mailbox; + +#ifdef __KERNEL__ + +#ifndef __cplusplus + +typedef struct rt_mailbox { + int magic; + SEM sndsem, rcvsem; + struct rt_task_struct *waiting_task, *owndby; + char *bufadr; + int size, fbyte, lbyte, avbs, frbs; + spinlock_t lock; +#ifdef CONFIG_RTAI_RT_POLL + struct rt_poll_ql poll_recv; + struct rt_poll_ql poll_send; +#endif +} MBX; + +#else /* __cplusplus */ +extern "C" { +#endif /* !__cplusplus */ + +int __rtai_mbx_init(void); + +void __rtai_mbx_exit(void); + +RTAI_SYSCALL_MODE int rt_typed_mbx_init(struct rt_mailbox *mbx, int size, int qtype); + +int rt_mbx_init(struct rt_mailbox *mbx, int size); + +RTAI_SYSCALL_MODE int rt_mbx_delete(struct rt_mailbox *mbx); + +RTAI_SYSCALL_MODE int _rt_mbx_send(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_send(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_send(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_send_wp(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_send_wp(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_send_wp(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_send_if(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_send_if(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_send_if(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_send_until(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME timei, int space); +static inline int rt_mbx_send_until(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME time) +{ + return _rt_mbx_send_until(mbx, msg, msg_size, time, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_send_timed(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay, int space); +static inline int rt_mbx_send_timed(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay) +{ + return _rt_mbx_send_timed(mbx, msg, msg_size, delay, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_ovrwr_send(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_ovrwr_send(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_ovrwr_send(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_evdrp(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_evdrp(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_evdrp(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_receive(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_receive(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_receive(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_receive_wp(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_receive_wp(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_receive_wp(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_receive_if(struct rt_mailbox *mbx, void *msg, int msg_size, int space); +static inline int rt_mbx_receive_if(struct rt_mailbox *mbx, void *msg, int msg_size) +{ + return _rt_mbx_receive_if(mbx, msg, msg_size, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_receive_until(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME time, int space); +static inline int rt_mbx_receive_until(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME time) +{ + return _rt_mbx_receive_until(mbx, msg, msg_size, time, 1); +} + +RTAI_SYSCALL_MODE int _rt_mbx_receive_timed(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay, int space); +static inline int rt_mbx_receive_timed(struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay) +{ + return _rt_mbx_receive_timed(mbx, msg, msg_size, delay, 1); +} + +RTAI_SYSCALL_MODE struct rt_mailbox *_rt_typed_named_mbx_init(unsigned long mbx_name, int size, int qtype); +static inline struct rt_mailbox *rt_typed_named_mbx_init(const char *mbx_name, int size, int qtype) +{ + return _rt_typed_named_mbx_init(nam2num(mbx_name), size, qtype); +} + +RTAI_SYSCALL_MODE int rt_named_mbx_delete(struct rt_mailbox *mbx); + +#define rt_named_mbx_init(mbx_name, size) rt_typed_named_mbx_init(mbx_name, size, FIFO_Q) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +RTAI_PROTO(struct rt_mailbox *, rt_typed_mbx_init, (unsigned long name, int size, int qtype)) +{ + struct { unsigned long name; long size; long qtype; } arg = { name, size, qtype }; + return (struct rt_mailbox *)rtai_lxrt(BIDX, SIZARG, LXRT_MBX_INIT, &arg).v[LOW]; +} + +/** + * @ingroup lxrt + * Initialize mailbox. + * + * Initializes a mailbox referred to by @a name of size @a size. + * + * It is important to remark that the returned task pointer cannot be used + * directly, they are for kernel space data, but just passed as arguments when + * needed. + * + * @return On success a pointer to the mail box to be used in related calls. + * @return A 0 value is returned if it was not possible to setup the semaphore + * or something using the same name was found. + */ +#define rt_mbx_init(name, size) rt_typed_mbx_init(name, size, FIFO_Q) + +RTAI_PROTO(int, rt_mbx_delete, (struct rt_mailbox *mbx)) +{ + void *arg = mbx; + return rtai_lxrt(BIDX, SIZARG, LXRT_MBX_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(struct rt_mailbox *, rt_typed_named_mbx_init, (const char *name, int size, int type)) +{ + struct { unsigned long name; long size, type; } arg = { nam2num(name), size, type }; + return (struct rt_mailbox *)rtai_lxrt(BIDX, SIZARG, NAMED_MBX_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_named_mbx_delete, (struct rt_mailbox *mbx)) +{ + struct { struct rt_mailbox *mbx; } arg = { mbx }; + return rtai_lxrt(BIDX, SIZARG, NAMED_MBX_DELETE, &arg).i[LOW]; +} + +#define rt_named_mbx_init(mbx_name, size) \ + rt_typed_named_mbx_init(mbx_name, size, FIFO_Q) + +RTAI_PROTO(int, rt_mbx_send, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_SEND, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_send_wp, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_SEND_WP, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_send_if, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_SEND_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_send_until, (struct rt_mailbox *mbx, void *msg, int msg_size, RTIME time)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; RTIME time; long space; } arg = { mbx, (char *)msg, msg_size, time, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_SEND_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_send_timed, (struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; RTIME delay; long space; } arg = { mbx, (char *)msg, msg_size, delay, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_SEND_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_ovrwr_send, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_OVRWR_SEND, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_evdrp, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_EVDRP, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_receive, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_RECEIVE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_receive_wp, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_RECEIVE_WP, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_receive_if, (struct rt_mailbox *mbx, void *msg, int msg_size)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; long space; } arg = { mbx, (char *)msg, msg_size, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_RECEIVE_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_receive_until, (struct rt_mailbox *mbx, void *msg, int msg_size, RTIME time)) +{ + struct { struct rt_mailbox *mbx; void *msg; long msg_size; RTIME time; long space; } arg = { mbx, (char *)msg, msg_size, time, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_RECEIVE_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_mbx_receive_timed, (struct rt_mailbox *mbx, void *msg, int msg_size, RTIME delay)) +{ + struct { struct rt_mailbox *mbx; char *msg; long msg_size; RTIME delay; long space; } arg = { mbx, (char *)msg, msg_size, delay, 0 }; + return (int)rtai_lxrt(BIDX, SIZARG, MBX_RECEIVE_TIMED, &arg).i[LOW]; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#if !defined(__KERNEL__) || defined(__cplusplus) + +typedef struct rt_mailbox { + int opaque; +} MBX; + +#endif /* !__KERNEL__ || __cplusplus */ + +#endif /* !_RTAI_MBX_H */ diff --git a/include/rtai_modbus.h b/include/rtai_modbus.h new file mode 100644 index 0000000..578cbd6 --- /dev/null +++ b/include/rtai_modbus.h @@ -0,0 +1,12 @@ +#include + +const int DIGITAL_IN = 0; +const int DIGITAL_OUT = 1; +const int ANALOG_IN = 2; +const int IB_IL_AO = 3; + + +int rt_modbus_connect(char * hostname); +int rt_modbus_disconnect(int cno); +int rt_modbus_get(int cno, int type, uint16_t addr, uint16_t * value); +int rt_modbus_set(int cno, int type, uint16_t addr, uint16_t value); diff --git a/include/rtai_msg.h b/include/rtai_msg.h new file mode 100644 index 0000000..acc4cbd --- /dev/null +++ b/include/rtai_msg.h @@ -0,0 +1,706 @@ +/* + * Copyright (C) 2002 POSEIDON CONTROLS INC + * Copyright (C) 2002 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_MSG_H +#define _RTAI_MSG_H + +#include + +#define MSG_ERR ((RT_TASK *)RTE_OBJINV) + +struct rt_task_struct; +struct QueueBlock; +struct QueueHook; + +#ifdef __KERNEL__ + +typedef struct t_msgcb { /* Message control block structure. */ + int cmd; + void *sbuf; + size_t sbytes; + void *rbuf; + size_t rbytes; +} MSGCB; + +#define PROXY_MIN_STACK_SIZE 2048 + +struct proxy_t { + struct rt_task_struct *receiver; + int nmsgs, nbytes; + char *msg; +}; + +#define SYNCMSG 0 +#define PROXY -1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int __rtai_msg_init(void); + +void __rtai_msg_exit(void); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_send(struct rt_task_struct *task, + unsigned long msg); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_send_if(struct rt_task_struct *task, + unsigned long msg); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_send_until(struct rt_task_struct *task, + unsigned long msg, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_send_timed(struct rt_task_struct *task, + unsigned long msg, + RTIME delay); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_evdrp(struct rt_task_struct *task, + void *msg); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receive(struct rt_task_struct *task, + void *msg); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receive_if(struct rt_task_struct *task, + void *msg); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receive_until(struct rt_task_struct *task, + void *msg, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receive_timed(struct rt_task_struct *task, + void *msg, + RTIME delay); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpc(struct rt_task_struct *task, + unsigned long to_do, + void *result); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpc_if(struct rt_task_struct *task, + unsigned long to_do, + void *result); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpc_until(struct rt_task_struct *task, + unsigned long to_do, + void *result, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpc_timed(struct rt_task_struct *task, + unsigned long to_do, + void *result, + RTIME delay); + +RTAI_SYSCALL_MODE int rt_isrpc(struct rt_task_struct *task); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_return(struct rt_task_struct *task, + unsigned long result); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpcx(struct rt_task_struct *task, + void *smsg, + void *rmsg, + int ssize, + int rsize); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpcx_if(struct rt_task_struct *task, + void *smsg, + void *rmsg, + int ssize, + int rsize); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpcx_until(struct rt_task_struct *task, + void *smsg, + void *rmsg, + int ssize, + int rsize, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_rpcx_timed(struct rt_task_struct *task, + void *smsg, + void *rmsg, + int ssize, + int rsize, + RTIME delay); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_sendx(struct rt_task_struct *task, + void *msg, + int size); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_sendx_if(struct rt_task_struct *task, + void *msg, + int size); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_sendx_until(struct rt_task_struct *task, + void *msg, + int size, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_sendx_timed(struct rt_task_struct *task, + void *msg, + int size, + RTIME delay); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_returnx(struct rt_task_struct *task, + void *msg, + int size); + +#define rt_isrpcx(task) rt_isrpc(task) + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_evdrpx(struct rt_task_struct *task, + void *msg, + int size, + long *len); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receivex(struct rt_task_struct *task, + void *msg, + int size, + long *len); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receivex_if(struct rt_task_struct *task, + void *msg, + int size, + long *len); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receivex_until(struct rt_task_struct *task, + void *msg, + int size, + long *len, + RTIME time); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_receivex_timed(struct rt_task_struct *task, + void *msg, + int size, + long *len, + RTIME delay); + +struct rt_task_struct *__rt_proxy_attach(void (*func)(long), + struct rt_task_struct *task, + void *msg, + int nbytes, + int priority); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_proxy_attach(struct rt_task_struct *task, + void *msg, + int nbytes, + int priority); + +RTAI_SYSCALL_MODE int rt_proxy_detach(struct rt_task_struct *proxy); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_trigger(struct rt_task_struct *proxy); + +#define exist(name) rt_get_adr(nam2num(name)) + +RTAI_SYSCALL_MODE int rt_Send(pid_t pid, + void *smsg, + void *rmsg, + size_t ssize, + size_t rsize); + +RTAI_SYSCALL_MODE pid_t rt_Receive(pid_t pid, + void *msg, + size_t maxsize, + size_t *msglen); + +RTAI_SYSCALL_MODE pid_t rt_Creceive(pid_t pid, + void *msg, + size_t maxsize, + size_t *msglen, + RTIME delay); + +RTAI_SYSCALL_MODE int rt_Reply(pid_t pid, + void *msg, + size_t size); + +RTAI_SYSCALL_MODE pid_t rt_Proxy_attach(pid_t pid, + void *msg, + int nbytes, + int priority); + +RTAI_SYSCALL_MODE int rt_Proxy_detach(pid_t pid); + +RTAI_SYSCALL_MODE pid_t rt_Trigger(pid_t pid); + +RTAI_SYSCALL_MODE pid_t rt_Name_attach(const char *name); + +RTAI_SYSCALL_MODE pid_t rt_Name_locate(const char *host, + const char *name); + +RTAI_SYSCALL_MODE int rt_Name_detach(pid_t pid); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +RTAI_PROTO(struct rt_task_struct *,rt_send,(struct rt_task_struct *task, unsigned long msg)) +{ + struct { struct rt_task_struct *task; unsigned long msg; } arg = { task, msg }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SENDMSG, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_send_if,(struct rt_task_struct *task, unsigned long msg)) +{ + struct { struct rt_task_struct *task; unsigned long msg; } arg = { task, msg }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SEND_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_send_until,(struct rt_task_struct *task, unsigned long msg, RTIME time)) +{ + struct { struct rt_task_struct *task; unsigned long msg; RTIME time; } arg = { task, msg, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SEND_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_send_timed,(struct rt_task_struct *task, unsigned long msg, RTIME delay)) +{ + struct { struct rt_task_struct *task; unsigned long msg; RTIME delay; } arg = { task, msg, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SEND_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_evdrp,(struct rt_task_struct *task, void *msg)) +{ + struct { struct rt_task_struct *task; void *msg; } arg = { task, msg }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, EVDRP, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receive,(struct rt_task_struct *task, void *msg)) +{ + struct { struct rt_task_struct *task; void *msg; } arg = { task, msg }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVEMSG, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receive_if,(struct rt_task_struct *task, void *msg)) +{ + struct { struct rt_task_struct *task; void *msg; } arg = { task, msg }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVE_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receive_until,(struct rt_task_struct *task, void *msg, RTIME time)) +{ + struct { struct rt_task_struct *task; void *msg; RTIME time; } arg = { task, msg, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVE_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receive_timed,(struct rt_task_struct *task, void *msg, RTIME delay)) +{ + struct { struct rt_task_struct *task; void *msg; RTIME delay; } arg = { task, msg, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVE_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpc,(struct rt_task_struct *task, unsigned long to_do, void *result)) +{ + struct { struct rt_task_struct *task; unsigned long to_do; void *result; } arg = { task, to_do, result }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPCMSG, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpc_if,(struct rt_task_struct *task, unsigned long to_do, void *result)) +{ + struct { struct rt_task_struct *task; unsigned long to_do; void *result; } arg = { task, to_do, result }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPC_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpc_until,(struct rt_task_struct *task, unsigned long to_do, void *result, RTIME time)) +{ + struct { struct rt_task_struct *task; unsigned long to_do; void *result; RTIME time; } arg = { task, to_do, result, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPC_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpc_timed,(struct rt_task_struct *task, unsigned long to_do, void *result, RTIME delay)) +{ + struct { struct rt_task_struct *task; unsigned long to_do; void *result; RTIME delay; } arg = { task, to_do, result, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPC_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_isrpc,(struct rt_task_struct *task)) +{ + struct { struct rt_task_struct *task; } arg = { task }; + return (int)rtai_lxrt(BIDX, SIZARG, ISRPC, &arg).i[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_return,(struct rt_task_struct *task, unsigned long result)) +{ + struct { struct rt_task_struct *task; unsigned long result; } arg = { task, result }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RETURNMSG, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpcx,(struct rt_task_struct *task, void *smsg, void *rmsg, int ssize, int rsize)) +{ + struct { struct rt_task_struct *task; void *smsg; void *rmsg; long ssize; long rsize; } arg = { task, smsg, rmsg, ssize, rsize }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPCX, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpcx_if,(struct rt_task_struct *task, void *smsg, void *rmsg, int ssize, int rsize)) +{ + struct { struct rt_task_struct *task; void *smsg; void *rmsg; long ssize; long rsize; } arg = { task, smsg, rmsg, ssize, rsize }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPCX_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpcx_until,(struct rt_task_struct *task, void *smsg, void *rmsg, int ssize, int rsize, RTIME time)) +{ + struct { struct rt_task_struct *task; void *smsg; void *rmsg; long ssize; long rsize; RTIME time; } arg = { task, smsg, rmsg, ssize, rsize, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPCX_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_rpcx_timed,(struct rt_task_struct *task, void *smsg, void *rmsg, int ssize, int rsize, RTIME delay)) +{ + struct { struct rt_task_struct *task; void *smsg; void *rmsg; long ssize; long rsize; RTIME delay; } arg = { task, smsg, rmsg, ssize, rsize, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RPCX_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_sendx,(struct rt_task_struct *task, void *msg, int size)) +{ + struct { struct rt_task_struct *task; void *msg; long size; } arg = { task, msg, size }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SENDX, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_sendx_if,(struct rt_task_struct *task, void *msg, int size)) +{ + struct { struct rt_task_struct *task; void *msg; long size; } arg = { task, msg, size }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SENDX_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_sendx_until,(struct rt_task_struct *task, void *msg, int size, RTIME time)) +{ + struct { struct rt_task_struct *task; void *msg; long size; RTIME time; } arg = { task, msg, size, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SENDX_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_sendx_timed,(struct rt_task_struct *task, void *msg, long size, RTIME delay)) +{ + struct { struct rt_task_struct *task; void *msg; long size; RTIME delay; } arg = { task, msg, size, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, SENDX_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_returnx,(struct rt_task_struct *task, void *msg, int size)) +{ + struct { struct rt_task_struct *task; void *msg; long size; } arg = { task, msg, size }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RETURNX, &arg).v[LOW]; +} + +#define rt_isrpcx(task) rt_isrpc(task) + +RTAI_PROTO(struct rt_task_struct *,rt_evdrpx,(struct rt_task_struct *task, void *msg, int size, long *len)) +{ + struct { struct rt_task_struct *task; void *msg; long size; long *len; } arg = { task, msg, size, len }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, EVDRPX, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receivex,(struct rt_task_struct *task, void *msg, int size, long *len)) +{ + struct { struct rt_task_struct *task; void *msg; long size; long *len; } arg = { task, msg, size, len }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVEX, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receivex_if,(struct rt_task_struct *task, void *msg, int size, long *len)) +{ + struct { struct rt_task_struct *task; void *msg; long size; long *len; } arg = { task, msg, size, len }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVEX_IF, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receivex_until,(struct rt_task_struct *task, void *msg, int size, long *len, RTIME time)) +{ + struct { struct rt_task_struct *task; void *msg; long size; long *len; RTIME time; } arg = { task, msg, size, len, time }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVEX_UNTIL, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_receivex_timed,(struct rt_task_struct *task, void *msg, int size, long *len, RTIME delay)) +{ + struct { struct rt_task_struct *task; void *msg; long size; long *len; RTIME delay; } arg = { task, msg, size, len, delay }; + return (struct rt_task_struct *)rtai_lxrt(BIDX, SIZARG, RECEIVEX_TIMED, &arg).v[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_proxy_attach,(struct rt_task_struct *proxy, void *msg, int nbytes, int priority)) +{ + struct { struct rt_task_struct *proxy; void *msg; long nbytes, priority;} arg = { proxy, msg, nbytes, priority }; + return (struct rt_task_struct *) rtai_lxrt(BIDX, SIZARG, PROXY_ATTACH, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_proxy_detach,(struct rt_task_struct *proxy)) +{ + struct { struct rt_task_struct *proxy; } arg = { proxy }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, PROXY_DETACH, &arg).i[LOW]; +} + +RTAI_PROTO(struct rt_task_struct *,rt_trigger,(struct rt_task_struct *proxy)) +{ + struct { struct rt_task_struct *proxy; } arg = { proxy }; + return (struct rt_task_struct *) rtai_lxrt(BIDX, SIZARG, PROXY_TRIGGER, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_Send,(pid_t pid, void *smsg, void *rmsg, size_t ssize, size_t rsize )) +{ + struct { long pid; void *smsg; void *rmsg; unsigned long ssize, rsize;} arg = { pid, smsg, rmsg, ssize, rsize }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_SEND, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Receive,(pid_t pid, void *msg, size_t maxsize, size_t *msglen)) +{ + struct { long pid; void *msg; unsigned long maxsize; size_t *msglen; } arg = { pid, msg, maxsize, msglen }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_RECEIVE, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Creceive,(pid_t pid, void *msg, size_t maxsize, size_t *msglen, RTIME delay)) +{ + struct { long pid; void *msg; unsigned long maxsize; size_t *msglen; RTIME delay;} arg = { pid, msg, maxsize, msglen, delay }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_CRECEIVE, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Reply,(pid_t pid, void *msg, size_t size)) +{ + struct { long pid; void *msg; unsigned long size;} arg = { pid, msg, size }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_REPLY, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Proxy_attach,(pid_t pid, void *msg, int nbytes, int priority)) +{ + struct { long pid; void *msg; long nbytes, priority;} arg = { pid, msg, nbytes, priority }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_PROXY_ATTACH, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Proxy_detach,(pid_t pid)) +{ + struct { long pid; } arg = { pid }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_PROXY_DETACH, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Trigger,(pid_t pid)) +{ + struct { long pid; } arg = { pid }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_TRIGGER, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Alias_attach,(const char *name)) +{ + struct { const char *name; } arg = { name}; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_NAME_ATTACH, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_Name_locate,(const char *host, const char *name)) +{ + struct { const char *host, *name; } arg = { host, name }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_NAME_LOCATE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_Name_detach,(pid_t pid)) +{ + struct { long pid; } arg = { pid }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_NAME_DETACH, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_InitTickQueue,(void)) +{ + struct { unsigned long dummy; } arg; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_INITTICKQUEUE, &arg).i[LOW]; +} + +RTAI_PROTO(void, rt_ReleaseTickQueue,(void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, RT_RELEASETICKQUEUE, &arg); +} + +RTAI_PROTO(unsigned long, rt_qDynAlloc,(unsigned long n)) +{ + struct { unsigned long n; } arg = { n }; + return (unsigned long) rtai_lxrt(BIDX, SIZARG, RT_QDYNALLOC, &arg).i[LOW]; +} + +RTAI_PROTO(unsigned long, rt_qDynFree,(int n)) +{ + struct { long n; } arg = { n }; + return (unsigned long) rtai_lxrt(BIDX, SIZARG, RT_QDYNFREE, &arg).i[LOW]; +} + +RTAI_PROTO(struct QueueBlock *,rt_qDynInit,(struct QueueBlock **q, void (*fun)(void *, int), void *data, int evn )) +{ + struct QueueBlock *r; + + struct { struct QueueBlock **q; void (*fun)(void *, int), *data; long evn; } arg = { 0, fun, data, evn }; + r = (struct QueueBlock *) rtai_lxrt(BIDX, SIZARG, RT_QDYNINIT, &arg).v[LOW]; + if (q) *q = r; + return r; +} + +RTAI_PROTO(void, rt_qBlkWait,(struct QueueBlock *q, RTIME t)) +{ + struct { struct QueueBlock *q; RTIME t; } arg = { q, t } ; + rtai_lxrt(BIDX, SIZARG, RT_QBLKWAIT, &arg); +} + +RTAI_PROTO(void, rt_qBlkRepeat,(struct QueueBlock *q, RTIME t)) +{ + struct { struct QueueBlock *q; RTIME t; } arg = { q, t } ; + rtai_lxrt(BIDX, SIZARG, RT_QBLKREPEAT, &arg); +} + +RTAI_PROTO(void, rt_qBlkSoon,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKSOON, &arg); +} + +RTAI_PROTO(void, rt_qBlkDequeue,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKDEQUEUE, &arg); +} + +RTAI_PROTO(void, rt_qBlkCancel,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKCANCEL, &arg); +} + +RTAI_PROTO(void, rt_qBlkBefore,(struct QueueBlock *cur, struct QueueBlock *nxt)) +{ + struct { struct QueueBlock *cur, *nxt; } arg = { cur, nxt }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKBEFORE, &arg); +} + +RTAI_PROTO(void, rt_qBlkAfter,(struct QueueBlock *cur, struct QueueBlock *prv)) +{ + struct { struct QueueBlock *cur, *prv; } arg = { cur, prv }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKAFTER, &arg); +} + +RTAI_PROTO(struct QueueBlock *,rt_qBlkUnhook,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + return (struct QueueBlock *) rtai_lxrt(BIDX, SIZARG, RT_QBLKUNHOOK, &arg).v[LOW]; +} + +RTAI_PROTO(void, rt_qBlkRelease,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKRELEASE, &arg); +} + +RTAI_PROTO(void, rt_qBlkComplete,(struct QueueBlock *q)) +{ + struct { struct QueueBlock *q; } arg = { q }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKCOMPLETE, &arg); +} + +RTAI_PROTO(int, rt_qSync,(void)) +{ + struct { unsigned long long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, RT_QSYNC, &arg).i[LOW]; +} + +RTAI_PROTO(pid_t, rt_qReceive,(pid_t target, void *buf, size_t maxlen, size_t *msglen)) +{ + struct { long target; void *buf; unsigned long maxlen; size_t *msglen; } arg = { target, buf, maxlen, msglen }; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_QRECEIVE, &arg).i[LOW]; +} + +RTAI_PROTO(void, rt_qLoop,(void)) +{ + struct { unsigned long dummy; } arg; + rtai_lxrt(BIDX, SIZARG, RT_QLOOP, &arg); +} + +RTAI_PROTO(RTIME, rt_qStep,(void)) +{ + struct { unsigned long dummy; } arg; + return rtai_lxrt(BIDX, SIZARG, RT_QSTEP, &arg).rt; +} + +RTAI_PROTO(void, rt_qHookFlush,(struct QueueHook *h)) +{ + struct { struct QueueHook *h; } arg = { h }; + rtai_lxrt(BIDX, SIZARG, RT_QHOOKFLUSH, &arg); +} + +RTAI_PROTO(void, rt_qBlkAtHead,(struct QueueBlock *q, struct QueueHook *h)) +{ + struct { struct QueueBlock *q; struct QueueHook *h; } arg = { q, h }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKATHEAD, &arg); +} + +RTAI_PROTO(void, rt_qBlkAtTail,(struct QueueBlock *q, struct QueueHook *h)) +{ + struct { struct QueueBlock *q; struct QueueHook *h; } arg = { q, h }; + rtai_lxrt(BIDX, SIZARG, RT_QBLKATTAIL, &arg); +} + +RTAI_PROTO(struct QueueHook *,rt_qHookInit,(struct QueueHook **h, void (*c)(void *, struct QueueBlock *), void *a)) +{ + struct QueueHook *r; + struct { struct QueueHook **h; void (*c)(void *, struct QueueBlock *), *a;} arg = { 0, c, a }; + r = (struct QueueHook *) rtai_lxrt(BIDX, SIZARG, RT_QHOOKINIT, &arg).v[LOW]; + if (h) *h = r; + return r; +} + +RTAI_PROTO(void, rt_qHookRelease,(struct QueueHook *h)) +{ + struct { struct QueueHook *h; } arg = { h }; + rtai_lxrt(BIDX, SIZARG, RT_QHOOKRELEASE, &arg); +} + +RTAI_PROTO(void, rt_qBlkSchedule,(struct QueueBlock *q, RTIME t)) +{ + struct { struct QueueBlock *q; RTIME t; } arg = { q, t } ; + rtai_lxrt(BIDX, SIZARG, RT_QBLKSCHEDULE, &arg); +} + +RTAI_PROTO(struct QueueHook *,rt_GetTickQueueHook,(void)) +{ + struct { unsigned long dummy; } arg; + return (struct QueueHook *) rtai_lxrt(BIDX, SIZARG, RT_GETTICKQUEUEHOOK, &arg).v[LOW]; +} + +RTAI_PROTO(pid_t, rt_vc_reserve,( void )) +{ + struct { unsigned long dummy; } arg; + return (pid_t) rtai_lxrt(BIDX, SIZARG, RT_VC_RESERVE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_vc_attach,(pid_t pid)) +{ + struct { long pid; } arg = { pid }; + return rtai_lxrt(BIDX, SIZARG, RT_VC_ATTACH, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_vc_release,(pid_t pid)) +{ + struct { long pid; } arg = { pid }; + return rtai_lxrt(BIDX, SIZARG, RT_VC_RELEASE, &arg).i[LOW]; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#if !defined(__KERNEL__) || defined(__cplusplus) + +typedef struct t_msgcb { + int opaque; +} MSGCB; + +#endif /* !__KERNEL__ || __cplusplus */ + +#endif /* !_RTAI_MSG_H */ diff --git a/include/rtai_nam2num.h b/include/rtai_nam2num.h new file mode 100644 index 0000000..9cd5c00 --- /dev/null +++ b/include/rtai_nam2num.h @@ -0,0 +1,136 @@ +/** + * @ingroup shm + * @ingroup lxrt + * @ingroup tasklets + * @file + * + * Conversion between 6 characters strings and unsigned long identifiers. + * + * Convert a 6 characters string to un unsigned long, and vice versa, to be used + * as an dentifier for RTAI services, symmetrically available in user and kernel + * space, e.g. @ref shm "shared memory" and @ref lxrt "LXRT and LXRT-INFORMED". + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999-2013 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_NAM2NUM_H +#define _RTAI_NAM2NUM_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#ifdef __KERNEL__ + +#include +#include +#define NAM2NUM_PROTO(type, name, arglist) static inline type name arglist + +#else + +#include +#include +#define NAM2NUM_PROTO RTAI_PROTO + +#endif + +#define MAX_NAM2NUM 4096000003UL // nam2num("$$$$$$") + 2 + +/** + * Convert a 6 characters string to an unsigned long. + * + * Converts a 6 characters string name containing an alpha numeric identifier + * to its corresponding unsigned long identifier. + * + * @param name is the name to be converted. + * + * Allowed characters are: + * - english letters (no difference between upper and lower case, the latter + * will always be translated to upper case); + * - decimal digits; + * - '_', '@', '.' and another character of your choice, the latter will + * always be treated as a $ and converted back as such by num2nam(). + * + * @return the unsigned long associated with @a name. + */ +NAM2NUM_PROTO(unsigned long, nam2num, (const char *name)) +{ + unsigned long retval = 0; + int c, i; + + for (i = 0; i < 6; i++) { + if (!(c = name[i])) { + break; + } + if (islower(c)) { + c += (10 - 'a'); + } else if (isupper(c)) { + c += (10 - 'A'); + } else if (isdigit(c)) { + c -= '0'; + } else { + c = c == '_' ? 36 : c == '@' ? 37 : c == '.' ? 38 : 39; + } + retval = retval*40 + c; + } + return i > 0 ? retval + 2 : 0xFFFFFFFF; +} + +/** + * Convert an unsigned long identifier back to its corresponding 6 characters + * string. + * + * @param num is the unsigned long identifier whose alphanumeric name string has + * to be evaluated; + * + * @param name is a pointer to a 6 characters buffer where the identifier will + * be returned. Recall to dimension it at least to 7. + */ +NAM2NUM_PROTO(void, num2nam, (unsigned long num, char *name)) +{ + int c, i, k, q; + if (num >= MAX_NAM2NUM) { + strncpy(name, "|null|", 7); + return; + } + i = 5; + num -= 2; + while (num && i >= 0) { + q = num/40; + c = num - q*40; + num = q; + if (c < 36) { + name[i--] = c > 9 ? c + 'A' - 10 : c + '0'; + } else { + name[i--] = c == 36 ? '_' : c == 37 ? '@' : c == 38 ? '.' : '$'; + } + } + for (k = 0; i < 5; k++) { + name[k] = name[++i]; + } + name[k] = 0; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_RTAI_NAM2NUM_H */ diff --git a/include/rtai_names.h b/include/rtai_names.h new file mode 100644 index 0000000..b9eca94 --- /dev/null +++ b/include/rtai_names.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2000 POSEIDON CONTROLS INC + * + * 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, see . + * + */ + +#ifndef _RTAI_NAMES_H +#define _RTAI_NAMES_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +pid_t rt_Name_attach(const char *name); + +pid_t rt_Name_locate(const char *host, + const char *name); + +int rt_Name_detach(pid_t pid); + +void rt_boom(void); + +void rt_stomp(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_RTAI_NAMES_H */ diff --git a/include/rtai_prinher.h b/include/rtai_prinher.h new file mode 100644 index 0000000..28c11af --- /dev/null +++ b/include/rtai_prinher.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2006-2008 Paolo Mantegazza + * + * 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, see . + * + */ + + +#ifndef _RTAI_PRINHER_H +#define _RTAI_PRINHER_H + +#include + +#ifdef __KERNEL__ + +#ifdef CONFIG_RTAI_FULL_PRINHER + +#define task_owns_sems(task) ((task)->resq.next != &(task)->resq) + +static inline void enqueue_resqel(QUEUE *resqel, RT_TASK *resownr) +{ + QUEUE *resq; + resqel->next = resq = &resownr->resq; + (resqel->prev = resq->prev)->next = resqel; + resq->prev = resqel; +} + +#define enqueue_resqtsk(resownr) + +#define RESQEL_TASK ((((QUEUE *)resqel->task)->next)->task) + +static inline int _set_task_prio_from_resq(RT_TASK *resownr) +{ + int hprio; + RT_TASK *task; + QUEUE *resq, *resqel; + hprio = resownr->base_priority; + resqel = resq = &resownr->resq; + while ((resqel = resqel->next) != resq && (task = RESQEL_TASK) && task->priority < hprio) { + hprio = task->priority; + } + return hprio; +} + +static inline int dequeue_resqel_reset_task_priority(QUEUE *resqel, RT_TASK *resownr) +{ + int hprio, prio; + QUEUE *q; + (resqel->prev)->next = resqel->next; + (resqel->next)->prev = resqel->prev; + hprio = _set_task_prio_from_resq(resownr); + return renq_ready_task(resownr, ((q = resownr->msg_queue.next) != &resownr->msg_queue && (prio = (q->task)->priority) < hprio) ? prio : hprio); +} + +static inline int set_task_prio_from_resq(RT_TASK *resownr) +{ + int hprio, prio; + QUEUE *q; + hprio = _set_task_prio_from_resq(resownr); + return renq_ready_task(resownr, ((q = resownr->msg_queue.next) != &resownr->msg_queue && (prio = (q->task)->priority) < hprio) ? prio : hprio); +} + +#else /* !CONFIG_RTAI_FULL_PRINHER */ + +#define task_owns_sems(task) ((task)->owndres) + +#define enqueue_resqel(resqel, task) \ + do { (task)->owndres++; } while (0) + +#define enqueue_resqtsk(task) +// do { (task)->owndres += RPCINC; } while (0) + +static inline int _set_task_prio_from_resq(RT_TASK *resownr) +{ + QUEUE *q; + int prio; + return renq_ready_task(resownr, ((q = resownr->msg_queue.next) != &resownr->msg_queue && (prio = (q->task)->priority) < resownr->base_priority) ? prio : resownr->base_priority); +} + +static inline int dequeue_resqel_reset_task_priority(QUEUE *resqel, RT_TASK *resownr) +{ + if (--resownr->owndres <= 0) { + resownr->owndres = 0; + return _set_task_prio_from_resq(resownr); + } + return 0; +} + +static inline int set_task_prio_from_resq(RT_TASK *resownr) +{ + return !resownr->owndres ? _set_task_prio_from_resq(resownr) : 0; +} + +#endif /* CONFIG_RTAI_FULL_PRINHER */ + +#define dequeue_resqel_reset_current_priority(resqel, rt_current) \ + dequeue_resqel_reset_task_priority(resqel, rt_current) + +#define set_current_prio_from_resq(rt_current) \ + set_task_prio_from_resq(rt_current) + +#define task_owns_msgs(task) ((task)->msg_queue.next != &(task)->msg_queue) +#define task_owns_res(task) (task_owns_sems(task) || task_owns_msgs(task)) + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_PRINHER_H */ diff --git a/include/rtai_proc_fs.h b/include/rtai_proc_fs.h new file mode 100644 index 0000000..e34abcc --- /dev/null +++ b/include/rtai_proc_fs.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1999-2017 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_PROC_FS_H +#define _RTAI_PROC_FS_H + +extern struct proc_dir_entry *rtai_proc_root; + +#include + +#define PROC_READ_FUN(read_fun_name) \ + read_fun_name(struct seq_file *pf, void *v) + +#define PROC_READ_OPEN_OPS(rtai_proc_fops, read_fun_name) \ +\ +static int rtai_proc_open(struct inode *inode, struct file *file) { \ + return single_open(file, read_fun_name, NULL); \ +} \ +\ +static const struct file_operations rtai_proc_fops = { \ + .owner = THIS_MODULE, \ + .open = rtai_proc_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release \ +}; + +static inline void *CREATE_PROC_ENTRY(const char *name, umode_t mode, void *parent, const struct file_operations *proc_fops) +{ + return !parent ? proc_mkdir(name, NULL) : proc_create(name, mode, parent, proc_fops); +} + +#define SET_PROC_READ_ENTRY(entry, read_fun) do { } while(0) + +#define PROC_PRINT_VARS + +#define PROC_PRINT(fmt, args...) \ + do { seq_printf(pf, fmt, ##args); } while(0) + +#define PROC_PRINT_RETURN do { goto done; } while(0) + +#define PROC_PRINT_DONE do { return 0; } while(0) + +// End of proc print macros + +#endif /* !_RTAI_PROC_FS_H */ diff --git a/include/rtai_proxies.h b/include/rtai_proxies.h new file mode 100644 index 0000000..a0c7c65 --- /dev/null +++ b/include/rtai_proxies.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2000 Pierre Cloutier + * Copyright (C) 2000 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_PROXIES_H +#define _RTAI_PROXIES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +// Create a generic proxy task. +RT_TASK *__rt_proxy_attach(void (*func)(long), + RT_TASK *task, + void *msg, + int nbytes, + int priority); + +// Create a raw proxy task. +RTAI_SYSCALL_MODE RT_TASK *rt_proxy_attach(RT_TASK *task, + void *msg, + int nbytes, + int priority); + +// Delete a proxy task (a simplified specific rt_task_delete). +RTAI_SYSCALL_MODE int rt_proxy_detach(RT_TASK *proxy); + +//Trigger a proxy. +RTAI_SYSCALL_MODE RT_TASK *rt_trigger(RT_TASK *proxy); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_RTAI_PROXIES_H */ diff --git a/include/rtai_registry.h b/include/rtai_registry.h new file mode 100644 index 0000000..b0d1a29 --- /dev/null +++ b/include/rtai_registry.h @@ -0,0 +1,96 @@ +/** + * @ingroup lxrt + * @file + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999 Paolo Mantegazza , + * @note Copyright © 2019 Alec Ari , + * Steve Papacharalambous . + * + * 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, see . + * + */ + +#ifndef _RTAI_REGISTRY_H +#define _RTAI_REGISTRY_H + +#include + +struct task_struct; + +struct rt_registry_entry { + unsigned long name; // Numerical representation of resource name + void *adr; // Physical rt memory address of resource + struct task_struct *tsk; // Linux task owner of the resource + int type; // Type of resource + unsigned short count; // Usage registry + unsigned short alink; + unsigned short nlink; +}; + +#define MAX_SLOTS CONFIG_RTAI_SCHED_LXRT_NUMSLOTS // Max number of registered objects + +#define IS_TASK 0 // Used to identify registered resources +#define IS_SEM 1 +#define IS_RWL 2 +#define IS_SPL 3 +#define IS_MBX 4 +#define IS_PRX 5 +#define IS_HPCK 6 + +#ifdef __KERNEL__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +unsigned long is_process_registered(struct task_struct *tsk); + +int rt_register(unsigned long nam, + void *adr, + int typ, + struct task_struct *tsk); + +int rt_drg_on_name(unsigned long name); + +int rt_drg_on_name_cnt(unsigned long name); + +int rt_drg_on_adr(void *adr); + +int rt_drg_on_adr_cnt(void *adr); + +RTAI_SYSCALL_MODE unsigned long rt_get_name(void *adr); + +RTAI_SYSCALL_MODE void *rt_get_adr(unsigned long name); + +void *rt_get_adr_cnt(unsigned long name); + +int rt_get_type(unsigned long name); + +int rt_get_registry_slot(int slot, struct rt_registry_entry *entry); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + +#define exist(name) rt_get_adr(nam2num(name)) + +#endif /* !_RTAI_REGISTRY_H */ diff --git a/include/rtai_rwl.h b/include/rtai_rwl.h new file mode 100644 index 0000000..4961652 --- /dev/null +++ b/include/rtai_rwl.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 1999-2003 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_RWL_H +#define _RTAI_RWL_H + +#include + +struct rtai_rwlock; + +#ifdef __KERNEL__ + +#ifndef __cplusplus + +typedef struct rtai_rwlock { + SEM wrmtx, + wrsem, + rdsem; +} RWL; + +#else /* __cplusplus */ +extern "C" { +#endif /* !__cplusplus */ + +RTAI_SYSCALL_MODE int rt_typed_rwl_init(RWL *rwl, int type); + +#define rt_rwl_init(rwl) rt_typed_rwl_init(rwl, RESEM_RECURS) + +RTAI_SYSCALL_MODE int rt_rwl_delete(struct rtai_rwlock *rwl); + +RTAI_SYSCALL_MODE RWL *_rt_named_rwl_init(unsigned long rwl_name); + +RTAI_SYSCALL_MODE int rt_named_rwl_delete(RWL *rwl); + +RTAI_SYSCALL_MODE int rt_rwl_rdlock(struct rtai_rwlock *rwl); + +RTAI_SYSCALL_MODE int rt_rwl_rdlock_if(struct rtai_rwlock *rwl); + +RTAI_SYSCALL_MODE int rt_rwl_rdlock_until(struct rtai_rwlock *rwl, RTIME time); + +RTAI_SYSCALL_MODE int rt_rwl_rdlock_timed(struct rtai_rwlock *rwl, RTIME delay); + +RTAI_SYSCALL_MODE int rt_rwl_wrlock(struct rtai_rwlock *rwl); + +RTAI_SYSCALL_MODE int rt_rwl_wrlock_if(struct rtai_rwlock *rwl); + +RTAI_SYSCALL_MODE int rt_rwl_wrlock_until(struct rtai_rwlock *rwl, RTIME time); + +RTAI_SYSCALL_MODE int rt_rwl_wrlock_timed(struct rtai_rwlock *rwl, RTIME delay); + +RTAI_SYSCALL_MODE int rt_rwl_unlock(struct rtai_rwlock *rwl); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define rt_rwl_init(rwl) rt_typed_rwl_init(rwl, RESEM_RECURS) + +RTAI_PROTO(struct rtai_rwlock *, rt_typed_rwl_init,(unsigned long name, int type)) +{ + struct { unsigned long name; long type; } arg = { name, type }; + return (struct rtai_rwlock *)rtai_lxrt(BIDX, SIZARG, LXRT_RWL_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_rwl_delete,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, LXRT_RWL_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(struct rtai_rwlock *, rt_named_rwl_init,(const char *name)) +{ + struct { unsigned long name; } arg = { nam2num(name) }; + return (struct rtai_rwlock *)rtai_lxrt(BIDX, SIZARG, NAMED_RWL_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_named_rwl_delete,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, NAMED_RWL_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_rdlock,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, RWL_RDLOCK, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_rdlock_if,(struct rtai_rwlock *rwl)) +{ + struct { void *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, RWL_RDLOCK_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_rdlock_until,(struct rtai_rwlock *rwl, RTIME time)) +{ + struct { struct rtai_rwlock *rwl; RTIME time; } arg = { rwl, time }; + return rtai_lxrt(BIDX, SIZARG, RWL_RDLOCK_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_rdlock_timed,(struct rtai_rwlock *rwl, RTIME delay)) +{ + struct { struct rtai_rwlock *rwl; RTIME delay; } arg = { rwl, delay }; + return rtai_lxrt(BIDX, SIZARG, RWL_RDLOCK_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_wrlock,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, RWL_WRLOCK, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_wrlock_if,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, RWL_WRLOCK_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_wrlock_until,(struct rtai_rwlock *rwl, RTIME time)) +{ + struct { struct rtai_rwlock *rwl; RTIME time; } arg = { rwl, time }; + return rtai_lxrt(BIDX, SIZARG, RWL_WRLOCK_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_wrlock_timed,(struct rtai_rwlock *rwl, RTIME delay)) +{ + struct { struct rtai_rwlock *rwl; RTIME delay; } arg = { rwl, delay }; + return rtai_lxrt(BIDX, SIZARG, RWL_WRLOCK_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_rwl_unlock,(struct rtai_rwlock *rwl)) +{ + struct { struct rtai_rwlock *rwl; } arg = { rwl }; + return rtai_lxrt(BIDX, SIZARG, RWL_UNLOCK, &arg).i[LOW]; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#if !defined(__KERNEL__) || defined(__cplusplus) + +typedef struct rtai_rwlock { + int opaque; +} RWL; + +#endif /* !__KERNEL__ || __cplusplus */ + +#endif /* !_RTAI_RWL_H */ diff --git a/include/rtai_scb.h b/include/rtai_scb.h new file mode 100644 index 0000000..556e8c8 --- /dev/null +++ b/include/rtai_scb.h @@ -0,0 +1,332 @@ +/** + * @ingroup shm + * @file + * + * SCB stand for Shared (memory) Circular Buffer. It is a non blocking + * implementation for just a single writer (producer) and reader + * (consumer) and, under such a constraint, it can be a specific + * substitute for RTAI mailboxes. There are other constraints that + * must be satisfied, so it cannot be a general substitute for the more + * flexible RTAI mailboxes. In fact it provides just functions + * corresponding to RTAI mailboxes non blocking atomic send/receive of + * messages, i.e. the equivalents of rt_mbx_send_if and + * rt_mbx_receive_if. Moreover the circular buffer size must be >= to + * the largest message to be sent/received. At least the double of the + * largest message to be sent/received is strongly recommended. + * Thus sending/receiving a message either succeeds of fails. However + * thanks to the use of shared memory it should be more efficient than + * mailboxes in atomic exchanges of messages from kernel to user space. + * So it is a good candidate for supporting drivers development. + * + * @author Paolo Mantegazza + * + * @note Copyright © 2004-2008 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_SCB_H +#define _RTAI_SCB_H + +#include +#include + +#define SCB ((void *)(scb)) +#define SIZE ((volatile int *)scb)[-3] +#define FBYTE ((volatile int *)scb)[-2] +#define LBYTE ((volatile int *)scb)[-1] +#define HDRSIZ (3*sizeof(int)) + +struct task_struct; + +#ifdef __KERNEL__ + +#define RTAI_SCB_PROTO(type, name, arglist) static inline type name arglist + +#else + +#define RTAI_SCB_PROTO RTAI_PROTO + +#endif + +/** + * Allocate and initialize a shared memory circular buffer. + * + * @internal + * + * rt_scb_init is used to allocate and/or initialize a shared memory circular + * buffer. + * + * @param name is an unsigned long identifier; + * + * @param size is the size of the circular buffer. + * + * @param suprt is the kernel allocation method to be used, it can be: + * - USE_VMALLOC, use vmalloc; + * - USE_GFP_KERNEL, use kmalloc with GFP_KERNEL; + * - USE_GFP_ATOMIC, use kmalloc with GFP_ATOMIC; + * - USE_GFP_DMA, use kmalloc with GFP_DMA. + * - for use in kernel/(multi-threaded)user space only applications the + * user can use "suprt" to pass the address of any memory area (s)he has + * allocated on her/his own. In such a case the actual buffer should be + * greater than the requested size by the amount HDRSIZ at least. + * + * Since @a an unsigned long can be a clumsy identifier, services are provided + * to convert 6 characters identifiers to unsigned long, and vice versa. + * + * @see nam2num() and num2nam(). + * + * It must be remarked that only the very first call does a real allocation, + * any following call to allocate with the same name, from anywhere, will just + * increase the usage count and map the circular buffer to the user space, or + * return the related pointer to the already allocated buffer in kernel/user + * space. + * In any case the functions return a pointer to the circular buffer, + * appropriately mapped to the memory space in use. So if one is really sure + * that the named circular buffer has been initted already parameters "size" + * and "suprt" are not used and can be assigned any value. + * + * @returns a valid address on succes, you must use it, 0 on failure. + * + */ + +RTAI_SCB_PROTO(void *, rt_scb_init, (unsigned long name, int size, unsigned long suprt)) +{ + void *scb; + if (suprt > 1000) { + size -= HDRSIZ + 1; + scb = (void *)suprt; + } else { + scb = rt_shm_alloc(name, size + HDRSIZ + 1, suprt); + } + if (scb && !atomic_cmpxchg((atomic_t *)scb, 0, name)) { + ((int *)scb)[1] = ((int *)scb)[2] = 0; + ((int *)scb)[0] = size + 1; + } else { + while (!((int *)scb)[0]); + } + return scb ? scb + HDRSIZ : 0; +} + +/** + * Reset a shared memory circular buffer. + * + * @internal + * + * rt_scb_reset reinitializes a shared memory circular buffer. + * + * @param scb is the pointer returned when the buffer was initted. + * + */ + +RTAI_SCB_PROTO(void, rt_scb_reset, (void *scb)) +{ + LBYTE = FBYTE = 0; +} + +/** + * Free a shared memory circular buffer. + * + * @internal + * + * rt_scb_delete is used to release a previously allocated shared memory + * circular buffer. + * + * @param name is the unsigned long identifier used when the buffer was + * allocated; + * + * Analogously to what done by all the named allocation functions the freeing + * calls have just the effect of decrementing a usage count, unmapping any + * user space shared memory being freed, till the last is done, as that is the + * one the really frees any allocated memory. + * + * @returns the size of the succesfully freed buffer, 0 on failure. + * + * No need to call this function if you provided your own memory for the + * circular buffer. + * + */ + +RTAI_SCB_PROTO(int, rt_scb_delete, (unsigned long name)) +{ + return rt_shm_free(name); +} + +/** + * Get the number of bytes avaiable in a shared memory circular buffer. + * + * @internal + * + * rt_scb_avbs is used to get the number of bytes avaiable in a shared + * memory circular buffer. + * + * @param scb is the pointer handle returned when the buffer was initted. + * + * @returns the available number of bytes. + * + */ + +RTAI_SCB_PROTO (int, rt_scb_avbs, (void *scb)) +{ + int size = SIZE, fbyte = FBYTE, lbyte = LBYTE; + return (lbyte >= fbyte ? lbyte - fbyte : size + lbyte - fbyte); +} + +/** + * Get the number of bytes avaiable in a shared memory circular buffer. + * + * @internal + * + * rt_scb_bytes is used to get the number of bytes avaiable in a shared + * memory circular buffer; legacy alias for rt_scb_avbs. + * + * @param scb is the pointer handle returned when the buffer was initted. + * + * @returns the available number of bytes. + * + */ + +RTAI_SCB_PROTO (int, rt_scb_bytes, (void *scb)) +{ + return rt_scb_avbs(scb); +} + +/** + * Get the number of free bytes pace in a shared memory circular buffer. + * + * @internal + * + * rt_scb_frbs is used to get the number of free bytes space avaiable in a + * shared memory circular buffer. + * + * @param scb is the pointer handle returned when the buffer was initted. + * + * @returns the number of free bytes. + * + */ + +RTAI_SCB_PROTO (int, rt_scb_frbs, (void *scb)) +{ + int size = SIZE, fbyte = FBYTE, lbyte = LBYTE; + return (fbyte <= lbyte ? size + fbyte - lbyte : size - lbyte); +} + +/** + * @brief Gets (receives) a message, only if the whole message can be passed + * all at once. + * + * rt_scb_get tries to atomically receive the message @e msg of @e + * msg_size bytes from the shared memory circular buffer @e scb. + * It returns immediately and the caller is never blocked. + * + * @return On success, i.e. message got, it returns 0, msg_size on failure. + * + */ + +RTAI_SCB_PROTO(int, rt_scb_get, (void *scb, void *msg, int msg_size)) +{ + int size = SIZE, fbyte = FBYTE, lbyte = LBYTE; + if (msg_size > 0 && ((lbyte -= fbyte) >= 0 ? lbyte : size + lbyte) >= msg_size) { + int tocpy; + if ((tocpy = size - fbyte) > msg_size) { + memcpy(msg, SCB + fbyte, msg_size); + FBYTE = fbyte + msg_size; + } else { + memcpy(msg, SCB + fbyte, tocpy); + memcpy(msg + tocpy, SCB, msg_size -= tocpy); + FBYTE = msg_size; + } + return 0; + } + return msg_size; +} + +/** + * @brief eavedrops a message. + * + * rt_scb_evdrp atomically spies the message @e msg of @e + * msg_size bytes from the shared memory circular buffer @e scb. + * It returns immediately and the caller is never blocked. It is like + * rt_scb_get but leaves the message in the shared memory circular buffer. + * + * @return On success, i.e. message got, it returns 0, msg_size on failure. + * + */ + +RTAI_SCB_PROTO(int, rt_scb_evdrp, (void *scb, void *msg, int msg_size)) +{ + int size = SIZE, fbyte = FBYTE, lbyte = LBYTE; + if (msg_size > 0 && ((lbyte -= fbyte) >= 0 ? lbyte : size + lbyte) >= msg_size) { + int tocpy; + if ((tocpy = size - fbyte) > msg_size) { + memcpy(msg, SCB + fbyte, msg_size); + } else { + memcpy(msg, SCB + fbyte, tocpy); + memcpy(msg + tocpy, SCB, msg_size - tocpy); + } + return 0; + } + return msg_size; +} + +/** + * @brief Puts (sends) a message, only if the whole message can be passed all + * at once. + * + * rt_scb_put tries to atomically send the message @e msg of @e + * msg_size bytes to the shared memory circular buffer @e scb. + * It returns immediately and the caller is never blocked. + * + * @return On success, i.e. message put, it returns 0, msg_size on failure. + * + */ + +RTAI_SCB_PROTO(int, rt_scb_put, (void *scb, void *msg, int msg_size)) +{ + int size = SIZE, fbyte = FBYTE, lbyte = LBYTE; + if (msg_size > 0 && ((fbyte -= lbyte) <= 0 ? size + fbyte : fbyte) > msg_size) { + int tocpy; + if ((tocpy = size - lbyte) > msg_size) { + memcpy(SCB + lbyte, msg, msg_size); + LBYTE = lbyte + msg_size; + } else { + memcpy(SCB + lbyte, msg, tocpy); + memcpy(SCB, msg + tocpy, msg_size -= tocpy); + LBYTE = msg_size; + } + return 0; + } + return msg_size; +} + +RTAI_SCB_PROTO(int, rt_scb_ovrwr, (void *scb, void *msg, int msg_size)) +{ + int size = SIZE, lbyte = LBYTE; + if (msg_size > 0 && msg_size < size) { + int tocpy; + if ((tocpy = size - lbyte) > msg_size) { + memcpy(SCB + lbyte, msg, msg_size); + LBYTE = lbyte + msg_size; + } else { + memcpy(SCB + lbyte, msg, tocpy); + memcpy(SCB, msg + tocpy, msg_size -= tocpy); + LBYTE = msg_size; + } + return 0; + } + return msg_size; +} + +#endif /* _RTAI_SCB_H */ diff --git a/include/rtai_sched.h b/include/rtai_sched.h new file mode 100644 index 0000000..b4efa07 --- /dev/null +++ b/include/rtai_sched.h @@ -0,0 +1,528 @@ +/* + * Copyright (C) 1999-2017 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_SCHED_H +#define _RTAI_SCHED_H + +#include +#ifndef __KERNEL__ +#include +#include +#include +#include +#endif /* __KERNEL__ */ + +#define RT_SCHED_UP 1 +#define RT_SCHED_SMP 2 +#define RT_SCHED_MUP 3 + +#define RT_SCHED_HIGHEST_PRIORITY 0 +#define RT_SCHED_LOWEST_PRIORITY 0x3fffFfff +#define RT_SCHED_LINUX_PRIORITY 0x7fffFfff + +#define RT_RESEM_SUSPDEL (-0x7fffFfff) + +#define RT_SCHED_READY 1 +#define RT_SCHED_SUSPENDED 2 +#define RT_SCHED_DELAYED 4 +#define RT_SCHED_SEMAPHORE 8 +#define RT_SCHED_SEND 16 +#define RT_SCHED_RECEIVE 32 +#define RT_SCHED_RPC 64 +#define RT_SCHED_RETURN 128 +#define RT_SCHED_MBXSUSP 256 +#define RT_SCHED_SFTRDY 512 +#define RT_SCHED_POLL 1024 +#define RT_SCHED_SIGSUSP (1 << 15) + +#define RT_RWLINV (11) // keep this the highest +#define RT_CHGPORTERR (10) +#define RT_CHGPORTOK (9) +#define RT_NETIMOUT (8) +#define RT_DEADLOK (7) +#define RT_PERM (6) +#define RT_OBJINV (5) +#define RT_OBJREM (4) +#define RT_TIMOUT (3) +#define RT_UNBLKD (2) +#define RT_TMROVRN (1) // keep this the lowest, must be 1 +#define RTP_RWLINV ((void *)RT_RWLINV) +#define RTP_CHGPORTERR ((void *)RT_CHGPORTERR) +#define RTP_CHGPORTOK ((void *)RT_CHGPORTOK) +#define RTP_NETIMOUT ((void *)RT_NETIMOUT) +#define RTP_DEADLOK ((void *)RT_DEADLOK) +#define RTP_PERM ((void *)RT_PERM) +#define RTP_OBJINV ((void *)RT_OBJINV) +#define RTP_OBJREM ((void *)RT_OBJREM) +#define RTP_TIMOUT ((void *)RT_TIMOUT) +#define RTP_UNBLKD ((void *)RT_UNBLKD) +#define RTP_TMROVRN ((void *)RT_TMROVRN) +#define RTP_HIGERR (RTP_RWLINV) +#define RTP_LOWERR (RTP_TMROVRN) +#if CONFIG_RTAI_USE_NEWERR +#define RTE_BASE (0x3FFFFF00) +#define RTE_RWLINV (RTE_BASE + RT_RWLINV) +#define RTE_CHGPORTERR (RTE_BASE + RT_CHGPORTERR) +#define RTE_CHGPORTOK (RTE_BASE + RT_CHGPORTOK) +#define RTE_NETIMOUT (RTE_BASE + RT_NETIMOUT) +#define RTE_DEADLOK (RTE_BASE + RT_DEADLOK) +#define RTE_PERM (RTE_BASE + RT_PERM) +#define RTE_OBJINV (RTE_BASE + RT_OBJINV) +#define RTE_OBJREM (RTE_BASE + RT_OBJREM) +#define RTE_TIMOUT (RTE_BASE + RT_TIMOUT) +#define RTE_UNBLKD (RTE_BASE + RT_UNBLKD) +#define RTE_TMROVRN (RTE_BASE + RT_TMROVRN) +#define RTE_HIGERR (RTE_RWLINV) +#define RTE_LOWERR (RTE_TMROVRN) +#else +#define RTE_BASE (0xFFFB) +#define RTE_RWLINV (RTE_BASE + RT_RWLINV) +#define RTE_CHGPORTERR (RTE_BASE + RT_CHGPORTERR) +#define RTE_CHGPORTOK (RTE_BASE + RT_CHGPORTOK) +#define RTE_NETIMOUT (RTE_BASE + RT_NETIMOUT) +#define RTE_DEADLOK (RTE_BASE + RT_DEADLOK) +#define RTE_PERM (RTE_BASE + RT_PERM) +#define RTE_OBJINV (RTE_BASE + RT_OBJREM) +#define RTE_OBJREM (RTE_BASE + RT_OBJREM) +#define RTE_TIMOUT (RTE_BASE + RT_TIMOUT) +#define RTE_UNBLKD (RTE_BASE + RT_UNBLKD) +#define RTE_TMROVRN (RTE_BASE + RT_TMROVRN) +#define RTE_HIGERR (RTE_RWLINV) +#define RTE_LOWERR (RTE_TMROVRN) +#endif + +#define RT_EINTR (RTE_UNBLKD) + +#define rt_is_reterr(i) (i >= RTE_LOWERR) + +#define RT_IRQ_TASK 0 +#define RT_IRQ_TASKLET 1 +#define RT_IRQ_TASK_ERR 0x7FFFFFFF + +struct rt_task_struct; + +typedef struct rt_task_info { + RTIME period; long base_priority, priority; +} RT_TASK_INFO; + +#ifdef __KERNEL__ + +#include +#include + +#if defined(CONFIG_RTAI_LONG_TIMED_LIST) +#include +typedef struct rb_node rb_node_t; +typedef struct rb_root rb_root_t; +#endif + +#define RT_TASK_MAGIC 0x9ad25f6f // nam2num("rttask") + +#ifndef __cplusplus + +#include + +typedef struct rt_queue { + struct rt_queue *prev; + struct rt_queue *next; + struct rt_task_struct *task; +} QUEUE; + +struct mcb_t { + void *sbuf; + int sbytes; + void *rbuf; + int rbytes; +}; + +/*Exit handler functions are called like C++ destructors in rt_task_delete().*/ +typedef struct rt_ExitHandler { + struct rt_ExitHandler *nxt; + void (*fun) (void *arg1, int arg2); + void *arg1; + int arg2; +} XHDL; + +struct rt_heap_t { void *heap, *kadr, *uadr; }; + +#define RTAI_MAX_NAME_LENGTH 32 + +typedef struct rt_task_struct { + long *stack __attribute__ ((__aligned__ (L1_CACHE_BYTES))); + int uses_fpu; + int magic; + volatile int state, running; + unsigned long runnable_on_cpus; + long *stack_bottom; + volatile int priority; + int base_priority; + int policy; + int sched_lock_priority; + struct rt_task_struct *prio_passed_to; + RTIME period; + RTIME resume_time; + RTIME periodic_resume_time; + RTIME yield_time; + int rr_quantum, rr_remaining; + int suspdepth; + struct rt_queue queue; + int owndres; + struct rt_queue *blocked_on; + struct rt_queue msg_queue; + int tid; /* trace ID */ + unsigned long msg; + struct rt_queue ret_queue; + void (*signal)(void); + FPU_ENV fpu_reg __attribute__ ((__aligned__ (L1_CACHE_BYTES))); + struct rt_task_struct *prev, *next; + struct rt_task_struct *tprev, *tnext; + struct rt_task_struct *rprev, *rnext; + + /* For calls from LINUX. */ + long *fun_args; + long *bstack; + struct task_struct *lnxtsk; + long long retval; + char *msg_buf[2]; + long max_msg_size[2]; + char task_name[RTAI_MAX_NAME_LENGTH]; + void *system_data_ptr; + struct rt_task_struct *nextp, *prevp; + + RT_TRAP_HANDLER task_trap_handler[RTAI_NR_TRAPS]; + + long unblocked; + void *rt_signals; + volatile unsigned long pstate; + unsigned long usp_flags; + unsigned long usp_flags_mask; + unsigned long force_soft; + volatile int is_hard; + int kerrno; + + long busy_time_align; + void *linux_syscall_server; + + /* For use by watchdog. */ + int resync_frame; + + /* For use by exit handler functions. */ + XHDL *ExitHook; + + RTIME exectime[2]; + struct mcb_t mcb; + + /* Real time heaps. */ + struct rt_heap_t heap[2]; + + long scheduler; + +#ifdef CONFIG_RTAI_LONG_TIMED_LIST + rb_root_t rbr; + rb_node_t rbn; +#endif + struct rt_queue resq; + unsigned long resumsg; + int schedlat; +} RT_TASK __attribute__ ((__aligned__ (L1_CACHE_BYTES))); + +#else /* __cplusplus */ +extern "C" { +#endif /* !__cplusplus */ + +int set_rtext(RT_TASK *task, int priority, int uses_fpu, void(*signal)(void), unsigned int cpuid); + +int rt_task_init(struct rt_task_struct *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void)); + +int rt_task_init_cpuid(struct rt_task_struct *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void), + unsigned run_on_cpu); + +void rt_thread_create(void *fun, void *args, struct task_struct **thread); + +RT_TASK *rt_thread_init(unsigned long name, int priority, int make_hard, int policy, int cpus_allowed); + +int rt_thread_delete(RT_TASK *rt_task); + + +int rt_kthread_init(struct rt_task_struct *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void)); + +int rt_kthread_init_cpuid(struct rt_task_struct *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void), + unsigned run_on_cpu); + +RTAI_SYSCALL_MODE void rt_set_runnable_on_cpus(struct rt_task_struct *task, + unsigned long cpu_mask); + +RTAI_SYSCALL_MODE void rt_set_runnable_on_cpuid(struct rt_task_struct *task, + unsigned cpuid); + +RTAI_SYSCALL_MODE void rt_set_sched_policy(struct rt_task_struct *task, + int policy, + int rr_quantum_ns); + +int rt_task_delete(struct rt_task_struct *task); + +int rt_get_task_state(struct rt_task_struct *task); + +void rt_gettimeorig(RTIME time_orig[]); + +int rt_get_timer_cpu(void); + +int rt_is_hard_timer_running(void); + +void rt_set_periodic_mode(void); + +void rt_set_oneshot_mode(void); + +RTAI_SYSCALL_MODE RTIME start_rt_timer(int period); + +#define start_rt_timer_ns(period) start_rt_timer(nano2count((period))) + +RTAI_SYSCALL_MODE void start_rt_apic_timers(struct apic_timer_setup_data *setup_mode, + unsigned rcvr_jiffies_cpuid); + +void stop_rt_timer(void); + +struct rt_task_struct *rt_whoami(void); + +int rt_sched_type(void); + +RTAI_SYSCALL_MODE int rt_task_signal_handler(struct rt_task_struct *task, + void (*handler)(void)); + +RTAI_SYSCALL_MODE int rt_task_use_fpu(struct rt_task_struct *task, + int use_fpu_flag); + +void rt_linux_use_fpu(int use_fpu_flag); + +RTAI_SYSCALL_MODE int rt_hard_timer_tick_count(void); + +RTAI_SYSCALL_MODE int rt_hard_timer_tick_count_cpuid(int cpuid); + +RTAI_SYSCALL_MODE RTIME count2nano(RTIME timercounts); + +RTAI_SYSCALL_MODE RTIME nano2count(RTIME nanosecs); + +RTAI_SYSCALL_MODE RTIME count2nano_cpuid(RTIME timercounts, unsigned cpuid); + +RTAI_SYSCALL_MODE RTIME nano2count_cpuid(RTIME nanosecs, unsigned cpuid); + +RTIME rt_get_time(void); + +RTAI_SYSCALL_MODE RTIME rt_get_time_cpuid(unsigned cpuid); + +RTIME rt_get_time_ns(void); + +RTAI_SYSCALL_MODE RTIME rt_get_time_ns_cpuid(unsigned cpuid); + +RTIME rt_get_cpu_time_ns(void); + +RTIME rt_get_real_time(void); + +RTIME rt_get_real_time_ns(void); + +int rt_get_prio(struct rt_task_struct *task); + +int rt_get_inher_prio(struct rt_task_struct *task); + +RTAI_SYSCALL_MODE int rt_task_get_info(RT_TASK *task, RT_TASK_INFO *task_info); + +RTAI_SYSCALL_MODE int rt_get_priorities(struct rt_task_struct *task, int *priority, int *base_priority); + +RTAI_SYSCALL_MODE void rt_spv_RMS(int cpuid); + +RTAI_SYSCALL_MODE int rt_change_prio(struct rt_task_struct *task, + int priority); + +void rt_sched_lock(void); + +void rt_sched_unlock(void); + +void rt_task_yield(void); + +RTAI_SYSCALL_MODE int rt_task_suspend(struct rt_task_struct *task); + +RTAI_SYSCALL_MODE int rt_task_suspend_if(struct rt_task_struct *task); + +RTAI_SYSCALL_MODE int rt_task_suspend_until(struct rt_task_struct *task, RTIME until); + +RTAI_SYSCALL_MODE int rt_task_suspend_timed(struct rt_task_struct *task, RTIME delay); + +RTAI_SYSCALL_MODE int rt_task_resume(struct rt_task_struct *task); + +RTAI_SYSCALL_MODE int rt_set_linux_syscall_mode(long sync_async, void (*callback_fun)(long, long)); + +struct linux_syscalls_list; +void rt_exec_linux_syscall(RT_TASK *rt_current, struct linux_syscalls_list *syscalls, struct pt_regs *regs); + +RTAI_SYSCALL_MODE void rt_return_linux_syscall(RT_TASK *task, unsigned long retval); + +RTAI_SYSCALL_MODE int rt_irq_wait(unsigned irq); + +RTAI_SYSCALL_MODE int rt_irq_wait_if(unsigned irq); + +RTAI_SYSCALL_MODE int rt_irq_wait_until(unsigned irq, RTIME until); + +RTAI_SYSCALL_MODE int rt_irq_wait_timed(unsigned irq, RTIME delay); + +RTAI_SYSCALL_MODE void rt_irq_signal(unsigned irq); + +RTAI_SYSCALL_MODE int rt_request_irq_task (unsigned irq, void *handler, int type, int affine2task); + +RTAI_SYSCALL_MODE int rt_release_irq_task (unsigned irq); + +RTAI_SYSCALL_MODE int rt_task_make_periodic_relative_ns(struct rt_task_struct *task, + RTIME start_delay, + RTIME period); + +RTAI_SYSCALL_MODE int rt_task_make_periodic(struct rt_task_struct *task, + RTIME start_time, + RTIME period); + +RTAI_SYSCALL_MODE void rt_task_set_resume_end_times(RTIME resume, + RTIME end); + +RTAI_SYSCALL_MODE int rt_set_resume_time(struct rt_task_struct *task, + RTIME new_resume_time); + +RTAI_SYSCALL_MODE int rt_set_period(struct rt_task_struct *task, + RTIME new_period); + +int rt_task_wait_period(void); + +void rt_schedule(void); + +RTIME next_period(void); + +RTAI_SYSCALL_MODE void rt_busy_sleep(int nanosecs); + +RTAI_SYSCALL_MODE int rt_sleep(RTIME delay); + +RTAI_SYSCALL_MODE int rt_sleep_until(RTIME time); + +RTAI_SYSCALL_MODE int rt_task_masked_unblock(struct rt_task_struct *task, unsigned long mask); + +#define rt_task_wakeup_sleeping(t) rt_task_masked_unblock(t, RT_SCHED_DELAYED) + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_named_task_init(const char *task_name, + void (*thread)(long), + long data, + int stack_size, + int prio, + int uses_fpu, + void(*signal)(void)); + +RTAI_SYSCALL_MODE struct rt_task_struct *rt_named_task_init_cpuid(const char *task_name, + void (*thread)(long), + long data, + int stack_size, + int prio, + int uses_fpu, + void(*signal)(void), + unsigned run_on_cpu); + +RTAI_SYSCALL_MODE int rt_named_task_delete(struct rt_task_struct *task); + +RT_TRAP_HANDLER rt_set_task_trap_handler(struct rt_task_struct *task, + unsigned vec, + RT_TRAP_HANDLER handler); + +static inline RTIME timeval2count(struct timeval *t) +{ + return nano2count(t->tv_sec*1000000000LL + t->tv_usec*1000); +} + +static inline void count2timeval(RTIME rt, struct timeval *t) +{ + t->tv_sec = rtai_ulldiv(count2nano(rt), 1000000000, (unsigned long *)&t->tv_usec); + t->tv_usec /= 1000; +} + +static inline RTIME timespec2count(const struct timespec *t) +{ + return nano2count(t->tv_sec*1000000000LL + t->tv_nsec); +} + +static inline void count2timespec(RTIME rt, struct timespec *t) +{ + t->tv_sec = rtai_ulldiv(count2nano(rt), 1000000000, (unsigned long *)&t->tv_nsec); +} + +static inline RTIME timespec2nanos(const struct timespec *t) +{ + return t->tv_sec*1000000000LL + t->tv_nsec; +} + +static inline void nanos2timespec(RTIME rt, struct timespec *t) +{ + t->tv_sec = rtai_ulldiv(rt, 1000000000, (unsigned long *)&t->tv_nsec); +} + +void rt_make_hard_real_time(RT_TASK *task); + +void rt_make_soft_real_time(RT_TASK *task); + +#ifdef __cplusplus +} +#else /* !__cplusplus */ + +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#if !defined(__KERNEL__) || defined(__cplusplus) + +typedef struct rt_task_struct { + int opaque; +} RT_TASK; + +typedef struct QueueBlock { + int opaque; +} QBLK; + +typedef struct QueueHook { + int opaque; +} QHOOK; + +#endif /* !__KERNEL__ || __cplusplus */ + +#endif /* !_RTAI_SCHED_H */ diff --git a/include/rtai_schedcore.h b/include/rtai_schedcore.h new file mode 100644 index 0000000..12885c1 --- /dev/null +++ b/include/rtai_schedcore.h @@ -0,0 +1,599 @@ +/* + * Copyright (C) 1999-2013 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + + +#ifndef _RTAI_SCHEDCORE_H +#define _RTAI_SCHEDCORE_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef OOM_DISABLE +#define RTAI_OOM_DISABLE() \ + do { current->signal->oom_score_adj = OOM_DISABLE; } while (0) +#else +#define RTAI_OOM_DISABLE() +#endif + +#define NON_RTAI_TASK_SUSPEND(task) \ + do { (task->lnxtsk)->state = TASK_SOFTREALTIME; } while (0) + +#define NON_RTAI_TASK_RESUME(ready_task) \ + do { pend_wake_up_srq(ready_task->lnxtsk, rtai_cpuid()); } while (0) + +#define REQUEST_RESUME_SRQs_STUFF() \ +do { \ + if (!(wake_up_srq[0].srq = hal_alloc_irq())) { \ + printk("*** ABORT, NO VIRQ AVAILABLE FOR THE WAKING UP SRQ. ***\n"); \ + return -1; \ + } \ + ipipe_request_irq(hal_root_domain, wake_up_srq[0].srq, (void *)wake_up_srq_handler, NULL, NULL); \ +} while (0) + +#define RELEASE_RESUME_SRQs_STUFF() \ +do { \ + ipipe_free_irq(hal_root_domain, wake_up_srq[0].srq); \ + hal_free_irq(wake_up_srq[0].srq); \ +} while (0) + +extern RT_TASK rt_smp_linux_task[]; + +extern RT_TASK *rt_smp_current[]; + +extern RTIME rt_smp_time_h[]; + +extern volatile int rt_sched_timed; + +RT_TASK *rt_get_base_linux_task(RT_TASK **base_linux_task); + +RT_TASK *rt_alloc_dynamic_task(void); + +void rt_enq_ready_edf_task(RT_TASK *ready_task); + +void rt_enq_ready_task(RT_TASK *ready_task); + +int rt_renq_ready_task(RT_TASK *ready_task, + int priority); + +void rt_rem_ready_task(RT_TASK *task); + +void rt_rem_ready_current(RT_TASK *rt_current); + +void rt_enq_timed_task(RT_TASK *timed_task); + +void rt_rem_timed_task(RT_TASK *task); + +void rt_dequeue_blocked(RT_TASK *task); + +#ifdef CONFIG_RTAI_MALLOC +#ifdef CONFIG_RTAI_MALLOC_BUILTIN +#define sched_mem_init() \ + { if(__rtai_heap_init() != 0) { \ + return(-ENOMEM); \ + } } +#define sched_mem_end() __rtai_heap_exit() +#else /* CONFIG_RTAI_MALLOC_BUILTIN */ +#define sched_mem_init() +#define sched_mem_end() +#endif /* !CONFIG_RTAI_MALLOC_BUILTIN */ +#define call_exit_handlers(task) __call_exit_handlers(task) +#define set_exit_handler(task, fun, arg1, arg2) __set_exit_handler(task, fun, arg1, arg2) +#else /* !CONFIG_RTAI_MALLOC */ +#define sched_mem_init() +#define sched_mem_end() +#define call_exit_handlers(task) +#define set_exit_handler(task, fun, arg1, arg2) +#endif /* CONFIG_RTAI_MALLOC */ + +#define SEMHLF 0x0000FFFF +#define RPCHLF 0xFFFF0000 +#define RPCINC 0x00010000 + +#define DECLARE_RT_CURRENT int cpuid; RT_TASK *rt_current +#define ASSIGN_RT_CURRENT rt_current = rt_smp_current[cpuid = rtai_cpuid()] +#define RT_CURRENT rt_smp_current[rtai_cpuid()] + +#define MAX_LINUX_RTPRIO 99 +#define MIN_LINUX_RTPRIO 1 + +#ifdef CONFIG_RTAI_SCHED_ISR_LOCK +void rtai_handle_isched_lock(int nesting); +#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */ + +#ifdef CONFIG_SMP +#define rt_time_h (rt_smp_time_h[cpuid]) +#define rt_linux_task (rt_smp_linux_task[cpuid]) +#else +#define rt_time_h (rt_smp_time_h[0]) +#define rt_linux_task (rt_smp_linux_task[0]) +#endif + +/* + * WATCH OUT for the max expected number of arguments of rtai funs and + * their scattered around different calling ways. + */ + +#define RTAI_MAX_FUN_ARGS 9 +struct fun_args { unsigned long a[RTAI_MAX_FUN_ARGS]; RTAI_SYSCALL_MODE long long (*fun)(unsigned long, ...); }; +//used in sys.c +#define RTAI_FUN_ARGS arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],arg[7],arg[RTAI_MAX_FUN_ARGS - 1] +//used in sched.c (generalised calls from soft threads) +#define RTAI_FUNARGS funarg->a[0],funarg->a[1],funarg->a[2],funarg->a[3],funarg->a[4],funarg->a[5],funarg->a[6],funarg->a[7],funarg->a[RTAI_MAX_FUN_ARGS - 1] + +#ifdef CONFIG_SMP + +static inline void send_sched_ipi(unsigned long dest) +{ + _send_sched_ipi(dest); +} + +#define RT_SCHEDULE_MAP(schedmap) \ + do { if (schedmap) send_sched_ipi(schedmap); } while (0) + +#define RT_SCHEDULE_MAP_BOTH(schedmap) \ + do { if (schedmap) send_sched_ipi(schedmap); rt_schedule(); } while (0) + +#define RT_SCHEDULE(task, cpuid) \ + do { \ + if ((task)->runnable_on_cpus != (cpuid)) { \ + send_sched_ipi(1 << (task)->runnable_on_cpus); \ + } else { \ + rt_schedule(); \ + } \ + } while (0) + +#define RT_SCHEDULE_BOTH(task, cpuid) \ + { \ + if ((task)->runnable_on_cpus != (cpuid)) { \ + send_sched_ipi(1 << (task)->runnable_on_cpus); \ + } \ + rt_schedule(); \ + } + +#else /* !CONFIG_SMP */ + +#define send_sched_ipi(dest) + +#define RT_SCHEDULE_MAP_BOTH(schedmap) rt_schedule() + +#define RT_SCHEDULE_MAP(schedmap) rt_schedule() + +#define RT_SCHEDULE(task, cpuid) rt_schedule() + +#define RT_SCHEDULE_BOTH(task, cpuid) rt_schedule() + +#endif /* CONFIG_SMP */ + +#define BASE_SOFT_PRIORITY 1000000000 + +#ifndef TASK_NOWAKEUP +#define TASK_NOWAKEUP TASK_UNINTERRUPTIBLE +#endif + +#define TASK_HARDREALTIME (TASK_INTERRUPTIBLE) // | TASK_NOWAKEUP) +#define TASK_RTAISRVSLEEP (TASK_INTERRUPTIBLE) // | TASK_NOWAKEUP) +#define TASK_SOFTREALTIME TASK_INTERRUPTIBLE + +static inline void enq_ready_edf_task(RT_TASK *ready_task) +{ + RT_TASK *task; +#ifdef CONFIG_SMP + task = rt_smp_linux_task[ready_task->runnable_on_cpus].rnext; +#else + task = rt_smp_linux_task[0].rnext; +#endif + while (task->policy < 0 && ready_task->period >= task->period) { + task = task->rnext; + } + task->rprev = (ready_task->rprev = task->rprev)->rnext = ready_task; + ready_task->rnext = task; +} + +struct epoch_struct { spinlock_t lock; volatile int touse; volatile RTIME time[2][2]; }; + +#ifdef CONFIG_RTAI_CLOCK_REALTIME +#define REALTIME2COUNT(rtime) \ + if (rtime > boot_epoch.time[boot_epoch.touse][0]) { \ + rtime -= boot_epoch.time[boot_epoch.touse][0]; \ + } +#else +#define REALTIME2COUNT(rtime) +#endif + +#define MAX_WAKEUP_SRQ (1 << 6) + +struct klist_t { int srq; volatile unsigned long in, out; void *task[MAX_WAKEUP_SRQ]; }; +extern struct klist_t wake_up_srq[]; + +#define pend_wake_up_srq(lnxtsk, cpuid) \ +do { \ + wake_up_srq[cpuid].task[wake_up_srq[cpuid].in++ & (MAX_WAKEUP_SRQ - 1)] = lnxtsk; \ + hal_pend_uncond(wake_up_srq[0].srq, cpuid); \ +} while (0) + +static inline void enq_ready_task(RT_TASK *ready_task) +{ + RT_TASK *task; + if (ready_task->is_hard) { +#ifdef CONFIG_SMP + task = rt_smp_linux_task[ready_task->runnable_on_cpus].rnext; +#else + task = rt_smp_linux_task[0].rnext; +#endif + while (ready_task->priority >= task->priority) { + if ((task = task->rnext)->priority < 0) break; + } + task->rprev = (ready_task->rprev = task->rprev)->rnext = ready_task; + ready_task->rnext = task; + } else { + ready_task->state |= RT_SCHED_SFTRDY; + NON_RTAI_TASK_RESUME(ready_task); + } +} + +static inline int renq_ready_task(RT_TASK *ready_task, int priority) +{ + int retval; + if ((retval = ready_task->priority != priority)) { + ready_task->priority = priority; + if (ready_task->state == RT_SCHED_READY) { + (ready_task->rprev)->rnext = ready_task->rnext; + (ready_task->rnext)->rprev = ready_task->rprev; + enq_ready_task(ready_task); + } + } + return retval; +} + +static inline void rem_ready_task(RT_TASK *task) +{ + if (task->state == RT_SCHED_READY) { + if (!task->is_hard) { + NON_RTAI_TASK_SUSPEND(task); + } +// task->unblocked = 0; + (task->rprev)->rnext = task->rnext; + (task->rnext)->rprev = task->rprev; + } +} + +static inline void rem_ready_current(RT_TASK *rt_current) +{ + if (!rt_current->is_hard) { + NON_RTAI_TASK_SUSPEND(rt_current); + } +// rt_current->unblocked = 0; + (rt_current->rprev)->rnext = rt_current->rnext; + (rt_current->rnext)->rprev = rt_current->rprev; +} + +#ifdef CONFIG_RTAI_LONG_TIMED_LIST + +/* BINARY TREE */ +static inline void enq_timed_task(RT_TASK *timed_task) +{ + RT_TASK *taskh, *tsknxt, *task; + rb_node_t **rbtn, *rbtpn = NULL; +#ifdef CONFIG_SMP + task = taskh = &rt_smp_linux_task[timed_task->runnable_on_cpus]; +#else + task = taskh = &rt_smp_linux_task[0]; +#endif + rbtn = &taskh->rbr.rb_node; + + while (*rbtn) { + rbtpn = *rbtn; + tsknxt = rb_entry(rbtpn, RT_TASK, rbn); + if (timed_task->resume_time > tsknxt->resume_time) { + rbtn = &(rbtpn)->rb_right; + } else { + rbtn = &(rbtpn)->rb_left; + task = tsknxt; + } + } + rb_link_node(&timed_task->rbn, rbtpn, rbtn); + rb_insert_color(&timed_task->rbn, &taskh->rbr); + task->tprev = (timed_task->tprev = task->tprev)->tnext = timed_task; + timed_task->tnext = task; +} + +#define rb_erase_task(task, cpuid) \ + rb_erase(&(task)->rbn, &rt_smp_linux_task[cpuid].rbr); + +#else /* !CONFIG_RTAI_LONG_TIMED_LIST */ + +/* LINEAR */ +static inline void enq_timed_task(RT_TASK *timed_task) +{ + RT_TASK *task; +#ifdef CONFIG_SMP + task = rt_smp_linux_task[timed_task->runnable_on_cpus].tnext; +#else + task = rt_smp_linux_task[0].tnext; +#endif + while (timed_task->resume_time > task->resume_time) { + task = task->tnext; + } + task->tprev = (timed_task->tprev = task->tprev)->tnext = timed_task; + timed_task->tnext = task; +} + +#define rb_erase_task(task, cpuid) + +#endif /* !CONFIG_RTAI_LONG_TIMED_LIST */ + +static inline void rem_timed_task(RT_TASK *task) +{ + if ((task->state & RT_SCHED_DELAYED)) { + (task->tprev)->tnext = task->tnext; + (task->tnext)->tprev = task->tprev; +#ifdef CONFIG_SMP + rb_erase_task(task, task->runnable_on_cpus); +#else + rb_erase_task(task, 0); +#endif + } +} + +static inline void wake_up_timed_tasks(int cpuid) +{ + RT_TASK *taskh, *task; +#ifdef CONFIG_SMP + task = (taskh = &rt_smp_linux_task[cpuid])->tnext; +#else + task = (taskh = &rt_smp_linux_task[0])->tnext; +#endif + if (task->resume_time - task->schedlat <= rt_time_h) { + do { + if ((task->state & RT_SCHED_SUSPENDED) && task->suspdepth > 0) { + task->suspdepth = 0; + } + if ((task->state &= ~(RT_SCHED_DELAYED | RT_SCHED_SUSPENDED | RT_SCHED_SEMAPHORE | RT_SCHED_RECEIVE | RT_SCHED_SEND | RT_SCHED_RPC | RT_SCHED_RETURN | RT_SCHED_MBXSUSP | RT_SCHED_POLL)) == RT_SCHED_READY) { + if (task->policy < 0) { + enq_ready_edf_task(task); + } else { + enq_ready_task(task); + } +#if ((CONFIG_RTAI_USER_BUSY_ALIGN_RET_DELAY > 0 || CONFIG_RTAI_KERN_BUSY_ALIGN_RET_DELAY > 0)) + task->busy_time_align = 1; +#endif + } + rb_erase_task(task, cpuid); + task = task->tnext; + } while (task->resume_time <= rt_time_h); +#ifdef CONFIG_SMP + rt_smp_linux_task[cpuid].tnext = task; + task->tprev = &rt_smp_linux_task[cpuid]; +#else + rt_smp_linux_task[0].tnext = task; + task->tprev = &rt_smp_linux_task[0]; +#endif + } +} + +#define get_time() rt_get_time() + +static inline void enqueue_blocked(RT_TASK *task, QUEUE *queue, int qtype) +{ + QUEUE *q; + task->blocked_on = (q = queue); + if (!qtype) { + while ((q = q->next) != queue && (q->task)->priority <= task->priority); + } + q->prev = (task->queue.prev = q->prev)->next = &(task->queue); + task->queue.next = q; +} + + +static inline void dequeue_blocked(RT_TASK *task) +{ + task->prio_passed_to = NULL; + (task->queue.prev)->next = task->queue.next; + (task->queue.next)->prev = task->queue.prev; + task->blocked_on = NULL; +} + +static inline unsigned long pass_prio(RT_TASK *to, RT_TASK *from) +{ + QUEUE *q, *blocked_on; +#ifdef CONFIG_SMP + RT_TASK *rhead; + unsigned long schedmap; + schedmap = 0; +#endif +// from->prio_passed_to = to; + while (to && to->priority > from->priority) { + to->priority = from->priority; + if (to->state == RT_SCHED_READY) { + if ((to->rprev)->priority > to->priority || (to->rnext)->priority < to->priority) { +#ifdef CONFIG_SMP + rhead = rt_smp_linux_task[to->runnable_on_cpus].rnext; +#endif + (to->rprev)->rnext = to->rnext; + (to->rnext)->rprev = to->rprev; + enq_ready_task(to); +#ifdef CONFIG_SMP + if (rhead != rt_smp_linux_task[to->runnable_on_cpus].rnext) { + __set_bit(to->runnable_on_cpus & 0x1F, &schedmap); + } +#endif + } + break; +// } else if ((void *)(q = to->blocked_on) > RTE_HIGERR && !((to->state & RT_SCHED_SEMAPHORE) && ((SEM *)q)->qtype)) { + } else if ((unsigned long)(blocked_on = to->blocked_on) > RTE_HIGERR && (((to->state & RT_SCHED_SEMAPHORE) && ((SEM *)blocked_on)->type > 0) || (to->state & (RT_SCHED_SEND | RT_SCHED_RPC | RT_SCHED_RETURN)))) { + if (to->queue.prev != blocked_on) { + q = blocked_on; + (to->queue.prev)->next = to->queue.next; + (to->queue.next)->prev = to->queue.prev; + while ((q = q->next) != blocked_on && (q->task)->priority <= to->priority); + q->prev = (to->queue.prev = q->prev)->next = &(to->queue); + to->queue.next = q; + if (to->queue.prev != blocked_on) { + break; + } + } + to = (to->state & RT_SCHED_SEMAPHORE) ? ((SEM *)blocked_on)->owndby : blocked_on->task; + } +// to = to->prio_passed_to; + } +#ifdef CONFIG_SMP + return schedmap; +#else + return 0; +#endif +} + +static inline RT_TASK *_rt_whoami(void) +{ +#ifdef CONFIG_SMP + RT_TASK *rt_current; + unsigned long flags; + flags = rt_global_save_flags_and_cli(); + rt_current = RT_CURRENT; + rt_global_restore_flags(flags); + return rt_current; +#else + return rt_smp_current[0]; +#endif +} + +static inline void __call_exit_handlers(RT_TASK *task) +{ + XHDL *pt, *tmp; + + pt = task->ExitHook; // Initialise ExitHook in rt_task_init() + while ( pt ) { + (*pt->fun) (pt->arg1, pt->arg2); + tmp = pt; + pt = pt->nxt; + rt_free(tmp); + } + task->ExitHook = 0; +} + +static inline XHDL *__set_exit_handler(RT_TASK *task, void (*fun) (void *, int), void *arg1, int arg2) +{ + XHDL *p; + + // exit handler functions are automatically executed at terminattion time by rt_task_delete() + // in the reverse order they were created (like C++ destructors behave). + if (task->magic != RT_TASK_MAGIC) return 0; + if (!(p = (XHDL *) rt_malloc (sizeof(XHDL)))) return 0; + p->fun = fun; + p->arg1 = arg1; + p->arg2 = arg2; + p->nxt = task->ExitHook; + return (task->ExitHook = p); +} + +static inline int rtai_init_features (void) + +{ +#ifdef CONFIG_RTAI_SEM_BUILTIN + __rtai_sem_init(); +#endif /* CONFIG_RTAI_SEM_BUILTIN */ +#ifdef CONFIG_RTAI_MSG_BUILTIN + __rtai_msg_init(); +#endif /* CONFIG_RTAI_MSG_BUILTIN */ +#ifdef CONFIG_RTAI_MBX_BUILTIN + __rtai_mbx_init(); +#endif /* CONFIG_RTAI_MBX_BUILTIN */ +#ifdef CONFIG_RTAI_FIFOS_BUILTIN + __rtai_fifos_init(); +#endif /* CONFIG_RTAI_FIFOS_BUILTIN */ +#ifdef CONFIG_RTAI_SHM_BUILTIN + __rtai_shm_init(); +#endif /* CONFIG_RTAI_SHM_BUILTIN */ +#ifdef CONFIG_RTAI_MATH_BUILTIN + __rtai_math_init(); +#endif /* CONFIG_RTAI_MATH_BUILTIN */ + + return 0; +} + +static inline void rtai_cleanup_features (void) { + +#ifdef CONFIG_RTAI_MATH_BUILTIN + __rtai_math_exit(); +#endif /* CONFIG_RTAI_MATH_BUILTIN */ +#ifdef CONFIG_RTAI_SHM_BUILTIN + __rtai_shm_exit(); +#endif /* CONFIG_RTAI_SHM_BUILTIN */ +#ifdef CONFIG_RTAI_FIFOS_BUILTIN + __rtai_fifos_exit(); +#endif /* CONFIG_RTAI_FIFOS_BUILTIN */ +#ifdef CONFIG_RTAI_MBX_BUILTIN + __rtai_mbx_exit(); +#endif /* CONFIG_RTAI_MBX_BUILTIN */ +#ifdef CONFIG_RTAI_MSG_BUILTIN + __rtai_msg_exit(); +#endif /* CONFIG_RTAI_MSG_BUILTIN */ +#ifdef CONFIG_RTAI_SEM_BUILTIN + __rtai_sem_exit(); +#endif /* CONFIG_RTAI_SEM_BUILTIN */ +} + +int rt_check_current_stack(void); + +int rt_kthread_init_old(RT_TASK *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void)); + +int rt_kthread_init_cpuid(RT_TASK *task, + void (*rt_thread)(long), + long data, + int stack_size, + int priority, + int uses_fpu, + void(*signal)(void), + unsigned int cpuid); + +#else /* !__KERNEL__ */ + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_SCHEDCORE_H */ diff --git a/include/rtai_sem.h b/include/rtai_sem.h new file mode 100644 index 0000000..d6f066e --- /dev/null +++ b/include/rtai_sem.h @@ -0,0 +1,429 @@ +/** + * @ingroup lxrt + * @file + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999-2003 Paolo Mantegazza + * @note Copyright © 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_SEM_H +#define _RTAI_SEM_H + +#include +#include +#include + +#define RT_SEM_MAGIC 0x3f83ebb // nam2num("rtsem") + +#define SEM_ERR (RTE_OBJINV) +#define SEM_TIMOUT (RTE_TIMOUT) + +struct rt_poll_s { void *what; unsigned long forwhat; }; + +// do not use 0 for any "forwhat" below +#define RT_POLL_NOT_TO_USE 0 +#define RT_POLL_MBX_RECV 1 +#define RT_POLL_MBX_SEND 2 +#define RT_POLL_SEM_WAIT_ALL 3 +#define RT_POLL_SEM_WAIT_ONE 4 + +#if defined(__KERNEL__) && !defined(__cplusplus) + +struct rt_poll_ql { QUEUE pollq; spinlock_t pollock; }; +struct rt_poll_enc { unsigned long offset; int (*topoll)(void *); }; +extern struct rt_poll_enc rt_poll_ofstfun[]; + +typedef struct rt_semaphore { + struct rt_queue queue; /* <= Must be first in struct. */ + int magic; + int type, restype; + int count; + struct rt_task_struct *owndby; + int qtype; + struct rt_queue resq; +#ifdef CONFIG_RTAI_RT_POLL + struct rt_poll_ql poll_wait_all; + struct rt_poll_ql poll_wait_one; +#endif +} SEM; + +#ifdef CONFIG_RTAI_RT_POLL + +RTAI_SYSCALL_MODE int _rt_poll(struct rt_poll_s *pdsa, unsigned long nr, RTIME timeout, int space); +static inline int rt_poll(struct rt_poll_s *pdsa, unsigned long nr, RTIME timeout) +{ + return _rt_poll(pdsa, nr, timeout, 1); +} + +void rt_wakeup_pollers(struct rt_poll_ql *ql, int reason); + +#else + +static inline int rt_poll(struct rt_poll_s *pdsa, unsigned long nr, RTIME timeout) +{ + return RTE_OBJINV; +} + +#define rt_wakeup_pollers(ql, reason) + +#endif + +#else /* !__KERNEL__ || __cplusplus */ + +typedef struct rt_semaphore { + int opaque; +} SEM; + +#endif /* __KERNEL__ && !__cplusplus */ + +typedef SEM CND; + +#ifdef __KERNEL__ + +#include + +typedef SEM psem_t; + +typedef SEM pmutex_t; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int __rtai_sem_init(void); + +void __rtai_sem_exit(void); + +RTAI_SYSCALL_MODE void rt_typed_sem_init(SEM *sem, + int value, + int type); + +RTAI_SYSCALL_MODE int rt_sem_delete(SEM *sem); + +RTAI_SYSCALL_MODE SEM *_rt_typed_named_sem_init(unsigned long sem_name, + int value, + int type, + unsigned long *handle); + +static inline SEM *rt_typed_named_sem_init(const char *sem_name, + int value, + int type) { + return _rt_typed_named_sem_init(nam2num(sem_name), value, type, NULL); +} + +RTAI_SYSCALL_MODE int rt_named_sem_delete(SEM *sem); + +void rt_sem_init(SEM *sem, + int value); + +RTAI_SYSCALL_MODE int rt_sem_signal(SEM *sem); + +RTAI_SYSCALL_MODE int rt_sem_broadcast(SEM *sem); + +RTAI_SYSCALL_MODE int rt_sem_wait(SEM *sem); + +RTAI_SYSCALL_MODE int rt_sem_wait_if(SEM *sem); + +int rt_cntsem_wait_if_and_lock(SEM *sem); + +RTAI_SYSCALL_MODE int rt_sem_wait_until(SEM *sem, + RTIME time); + +RTAI_SYSCALL_MODE int rt_sem_wait_timed(SEM *sem, + RTIME delay); + +RTAI_SYSCALL_MODE int rt_sem_wait_barrier(SEM *sem); + +RTAI_SYSCALL_MODE int rt_sem_count(SEM *sem); + +RTAI_SYSCALL_MODE int rt_cond_signal(CND *cnd); + +RTAI_SYSCALL_MODE int rt_cond_wait(CND *cnd, + SEM *mtx); + +RTAI_SYSCALL_MODE int rt_cond_wait_until(CND *cnd, + SEM *mtx, + RTIME time); + +RTAI_SYSCALL_MODE int rt_cond_wait_timed(CND *cnd, + SEM *mtx, + RTIME delay); + +#define rt_named_sem_init(sem_name, value) rt_typed_named_sem_init(sem_name, value, CNT_SEM) + +static inline int rt_psem_init(psem_t *sem, int pshared, unsigned int value) +{ + if (value < SEM_TIMOUT) { + rt_typed_sem_init(sem, value, pshared | PRIO_Q); + return 0; + } + return -EINVAL; +} + +static inline int rt_psem_destroy(psem_t *sem) +{ + if (rt_sem_wait_if(sem) >= 0) { + rt_sem_signal(sem); + return rt_sem_delete(sem); + } + return -EBUSY; +} + +static inline int rt_psem_wait(psem_t *sem) { + return rt_sem_wait(sem) < SEM_TIMOUT ? 0 : -1; +} + +static inline int rt_psem_timedwait(psem_t *sem, struct timespec *abstime) { + return rt_sem_wait_until(sem, timespec2count(abstime)) < SEM_TIMOUT ? 0 : -1; +} + +static inline int rt_psem_trywait(psem_t *sem) { + return rt_sem_wait_if(sem) > 0 ? 0 : -EAGAIN; +} + +static inline int rt_psem_post(psem_t *sem) { + return rt_sem_signal(sem); +} + +static inline int rt_psem_getvalue(psem_t *sem, int *sval) +{ + if ((*sval = rt_sem_wait_if(sem)) > 0) { + rt_sem_signal(sem); + } + return 0; +} + +static inline int rt_pmutex_init(pmutex_t *mutex, void *mutexattr) +{ + rt_typed_sem_init(mutex, 1, RES_SEM); + return 0; +} + +static inline int rt_pmutex_destroy(pmutex_t *mutex) +{ + if (rt_sem_wait_if(mutex) > 0) { + rt_sem_signal(mutex); + return rt_sem_delete(mutex); + } + return -EBUSY; +} + +static inline int rt_pmutex_lock(pmutex_t *mutex) { + return rt_sem_wait(mutex) < SEM_TIMOUT ? 0 : -EINVAL; +} + +static inline int rt_pmutex_trylock(pmutex_t *mutex) { + return rt_sem_wait_if(mutex) > 0 ? 0 : -EBUSY; +} + +static inline int rt_pmutex_timedlock(pmutex_t *sem, struct timespec *abstime) { + return rt_sem_wait_until(sem, timespec2count(abstime)) < SEM_TIMOUT ? 0 : -1; +} + +static inline int rt_pmutex_unlock(pmutex_t *mutex) { + return rt_sem_signal(mutex); +} + +#undef rt_mutex_init +#define rt_mutex_init(mtx) rt_typed_sem_init(mtx, 1, RES_SEM) +#define rt_mutex_delete(mtx) rt_sem_delete(mtx) +#define rt_mutex_destroy(mtx) rt_sem_delete(mtx) +#define rt_mutex_trylock(mtx) rt_sem_wait_if(mtx) +#define rt_mutex_lock(mtx) rt_sem_wait(mtx) +#define rt_mutex_timedlock(mtx, time) rt_sem_wait_until(mtx, time) +#define rt_mutex_unlock(mtx) rt_sem_signal(mtx) + +#define rt_cond_init(cnd) rt_typed_sem_init(cnd, 0, BIN_SEM | PRIO_Q) +#define rt_cond_delete(cnd) rt_sem_delete(cnd) +#define rt_cond_destroy(cnd) rt_sem_delete(cnd) +#define rt_cond_broadcast(cnd) rt_sem_broadcast(cnd) + +static inline int rt_cond_timedwait(CND *cnd, SEM *mtx, RTIME time) { + return rt_cond_wait_until(cnd, mtx, time) < SEM_TIMOUT ? 0 : -1; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +RTAI_PROTO(SEM *, rt_typed_sem_init,(unsigned long name, int value, int type)) +{ + struct { unsigned long name; long value, type; } arg = { name ? name : rt_get_name(NULL), value, type }; + return (SEM *)rtai_lxrt(BIDX, SIZARG, LXRT_SEM_INIT, &arg).v[LOW]; +} + +/** + * @ingroup lxrt + * Initialize a counting semaphore. + * + * Allocates and initializes a semaphore to be referred by @a name. + * + * @param name name of the semaphore. + * + * @param value is the initial value of the semaphore + * + * It is important to remark that the returned task pointer cannot be used + * directly, they are for kernel space data, but just passed as arguments when + * needed. + * + * @return a pointer to the semaphore to be used in related calls or 0 if an + * error has occured. + */ +#define rt_sem_init(name, value) rt_typed_sem_init(name, value, CNT_SEM) + +#define rt_named_sem_init(sem_name, value) \ + rt_typed_named_sem_init(sem_name, value, CNT_SEM) + +RTAI_PROTO(int, rt_sem_delete,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, LXRT_SEM_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(SEM *, rt_typed_named_sem_init,(const char *name, int value, int type)) +{ + struct { unsigned long name; long value, type; unsigned long *handle; } arg = { nam2num(name), value, type, NULL }; + return (SEM *)rtai_lxrt(BIDX, SIZARG, NAMED_SEM_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_named_sem_delete,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, NAMED_SEM_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_signal,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_SIGNAL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_broadcast,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_BROADCAST, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_wait,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_WAIT, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_wait_if,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_WAIT_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_wait_until,(SEM *sem, RTIME time)) +{ + struct { SEM *sem; RTIME time; } arg = { sem, time }; + return rtai_lxrt(BIDX, SIZARG, SEM_WAIT_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_wait_timed,(SEM *sem, RTIME delay)) +{ + struct { SEM *sem; RTIME delay; } arg = { sem, delay }; + return rtai_lxrt(BIDX, SIZARG, SEM_WAIT_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_wait_barrier,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_WAIT_BARRIER, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_sem_count,(SEM *sem)) +{ + struct { SEM *sem; } arg = { sem }; + return rtai_lxrt(BIDX, SIZARG, SEM_COUNT, &arg).i[LOW]; +} + +/** + * @ingroup lxrt + * Initialize a condition variable. + * + * Allocates and initializes a condition variable to be referred by @a name. + * + * @param name name of the condition variable. + * + * It is important to remark that the returned pointer cannot be used + * directly, it is for kernel space data, but just passed as arguments when + * needed. + * + * @return a pointer to the condition variable to be used in related calls or 0 + * if an error has occured. + */ +#define rt_cond_init(name) rt_typed_sem_init(name, 0, BIN_SEM) +#define rt_cond_delete(cnd) rt_sem_delete(cnd) +#define rt_cond_destroy(cnd) rt_sem_delete(cnd) +#define rt_cond_broadcast(cnd) rt_sem_broadcast(cnd) +#define rt_cond_timedwait(cnd, mtx, time) rt_cond_wait_until(cnd, mtx, time) + +RTAI_PROTO(int, rt_cond_signal,(CND *cnd)) +{ + struct { CND *cnd; } arg = { cnd }; + return rtai_lxrt(BIDX, SIZARG, COND_SIGNAL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_cond_wait,(CND *cnd, SEM *mutex)) +{ + struct { CND *cnd; SEM *mutex; } arg = { cnd, mutex }; + return rtai_lxrt(BIDX, SIZARG, COND_WAIT, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_cond_wait_until,(CND *cnd, SEM *mutex, RTIME time)) +{ + struct { CND *cnd; SEM *mutex; RTIME time; } arg = { cnd, mutex, time }; + return rtai_lxrt(BIDX, SIZARG, COND_WAIT_UNTIL, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_cond_wait_timed,(CND *cnd, SEM *mutex, RTIME delay)) +{ + struct { CND *cnd; SEM *mutex; RTIME delay; } arg = { cnd, mutex, delay }; + return rtai_lxrt(BIDX, SIZARG, COND_WAIT_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_poll, (struct rt_poll_s *pdsa, unsigned long nr, RTIME timeout)) +{ +#ifdef CONFIG_RTAI_RT_POLL + struct { struct rt_poll_s *pdsa; unsigned long nr; RTIME timeout; long space; } arg = { pdsa, nr, timeout, 0 }; + return rtai_lxrt(BIDX, SIZARG, SEM_RT_POLL, &arg).i[LOW]; +#else + (void)pdsa; (void)nr; (void)timeout; + return RTE_OBJINV; +#endif +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_SEM_H */ diff --git a/include/rtai_shm.h b/include/rtai_shm.h new file mode 100644 index 0000000..8f64984 --- /dev/null +++ b/include/rtai_shm.h @@ -0,0 +1,512 @@ +/** + * @ingroup shm + * @file + * + * Interface of the @ref shm "RTAI SHM module". + * + * @author Paolo Mantegazza + * + * @note Copyright © 1999-2017 Paolo Mantegazza + * @note Copyright © 2019 Alec Ari + * + * 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, see . + * + */ + +/* +ACKNOWLEDGMENTS: +- The suggestion and the code for mmapping at a user specified address is due to Trevor Woolven (trevw@zentropix.com). +*/ + + +#ifndef _RTAI_SHM_H +#define _RTAI_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @addtogroup shm + *@{*/ + +#define GLOBAL_HEAP_ID 0x9ac6d9e7 // nam2num("RTGLBH"); + +#define USE_VMALLOC 0 +#define USE_GFP_KERNEL 1 +#define USE_GFP_ATOMIC 2 +#define USE_GFP_DMA 3 + +/** + * Allocate a chunk of memory to be shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rtai_kalloc is used to allocate shared memory from kernel space. + * + * @param name is an unsigned long identifier; + * + * @param size is the amount of required shared memory; + * + * rtai_kmalloc is a legacy helper macro, the real job is carried out by a + * call to rt_shm_alloc() with the same name, size and with vmalloc support. + * This function should not be used in newly developed applications. See + * rt_shm_alloc for more details. + * + * @returns a valid address on succes, 0 on failure. + * + */ + +#define rtai_kmalloc(name, size) \ + rt_shm_alloc(name, size, USE_VMALLOC) // legacy + +/** + * Free a chunk of shared memory being shared inter-intra kernel modules and + * Linux processes. + * + * rtai_kfree is used to free a shared memory chunk from kernel space. + * + * @param name is the unsigned long identifier used when the memory was + * allocated; + * + * rtai_kfree is a legacy helper macro, the real job is carried out by a + * call to rt_shm_free with the same name. This function should not be used + * in newly developed applications. See rt_shm_free for more details. + * + * @returns the size of the succesfully freed memory, 0 on failure. + * + */ + +#define rtai_kfree(name) \ + rt_shm_free(name) // legacy + +#if defined(__KERNEL__) + +#include +#include +#include +#include + +#define UVIRT_TO_KVA(adr) uvirt_to_kva(pgd_offset_k(adr), (adr)) + +static inline int remap_page_range(struct vm_area_struct *vma, unsigned long uvaddr, unsigned long paddr, unsigned long size, pgprot_t prot) +{ + return remap_pfn_range(vma, uvaddr, paddr >> PAGE_SHIFT, size, prot); +} + +#include + +#include + +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + if (!pgd_none(*pgd) && !pgd_bad(*pgd)) { + pmd_t *pmd; + pmd = pmd_offset(pud_offset((void *)pgd, adr), adr); + if (!pmd_none(*pmd)) { + pte_t *ptep, pte; + ptep = pte_offset_kernel(pmd, adr); + pte = *ptep; + if (pte_present(pte)) { + return (((unsigned long)page_address(pte_page(pte))) | (adr & (PAGE_SIZE - 1))); + } + } + } + return 0UL; +} + +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + return virt_to_phys((void *)uvirt_to_kva(pgd_offset_k(adr), adr)); +} + +int __rtai_shm_init(void); + +void __rtai_shm_exit(void); + +void *rt_shm_alloc(unsigned long name, + int size, + int suprt); + +#define rt_shm_alloc_adr(adr, name, size) \ + rt_shm_alloc(name, size, suprt) + +RTAI_SYSCALL_MODE int rt_shm_free(unsigned long name); + +void *rt_heap_open(unsigned long name, + int size, + int suprt); + +#define rt_heap_open_adr(adr, name, size, suprt) \ + rt_heap_open(name, size, suprt) + +RTAI_SYSCALL_MODE void *rt_halloc(int size); + +RTAI_SYSCALL_MODE void rt_hfree(void *addr); + +RTAI_SYSCALL_MODE void *rt_named_halloc(unsigned long name, int size); + +RTAI_SYSCALL_MODE void rt_named_hfree(void *addr); + +void *rt_named_malloc(unsigned long name, + int size); + +void rt_named_free(void *addr); + +void *rvmalloc(unsigned long size); + +void rvfree(void *mem, + unsigned long size); + +int rvmmap(void *mem, + unsigned long memsize, + struct vm_area_struct *vma); + +void *rkmalloc(int *size, + int suprt); + +void rkfree(void *mem, + unsigned long size); + +int rkmmap(void *mem, + unsigned long memsize, + struct vm_area_struct *vma); + +#else /* !__KERNEL__ */ + +#include +#include +#include +#include +#include + +//#define SHM_USE_LXRT + +#define RTAI_SHM_DEV "/dev/rtai_shm" + +RTAI_PROTO (void *, _rt_shm_alloc, (void *start, unsigned long name, int size, int suprt, int isheap)) +{ + int hook; + void *adr = NULL; + + if ((hook = open(RTAI_SHM_DEV, O_RDWR)) <= 0) { + return NULL; + } else { + struct { unsigned long name; long arg, suprt; } arg = { name, size, suprt }; +#ifdef SHM_USE_LXRT + if ((size = rtai_lxrt(BIDX, SIZARG, SHM_ALLOC, &arg).i[LOW])) { +#else + if ((size = ioctl(hook, SHM_ALLOC, (unsigned long)(&arg)))) { +#endif + if ((adr = mmap(start, size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED, hook, 0)) == MAP_FAILED) {; +#ifdef SHM_USE_LXRT + rtai_lxrt(BIDX, sizeof(name), SHM_FREE, &name); +#else + ioctl(hook, SHM_FREE, &name); +#endif + } else if (isheap) { + arg.arg = (unsigned long)adr; +#ifdef SHM_USE_LXRT + rtai_lxrt(BIDX, SIZARG, HEAP_SET, &arg); +#else + ioctl(hook, HEAP_SET, &arg); +#endif + } + } + } + close(hook); + return adr; +} + +#define rt_shm_alloc(name, size, suprt) \ + _rt_shm_alloc(0, name, size, suprt, 0) + +#define rt_heap_open(name, size, suprt) \ + _rt_shm_alloc(0, name, size, suprt, 1) + +/** + * Allocate a chunk of memory to be shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rtai_malloc is used to allocate shared memory from user space. + * + * @param name is an unsigned long identifier; + * + * @param size is the amount of required shared memory; + * + * rtai_malloc is a legacy helper macro, the real job is carried out by a + * call to rt_shm_alloc() with the same name, size and with vmalloc support. + * This function should not be used in newly developed applications. See + * rt_shm_alloc fro more details. + * + * @returns a valid address on succes, on failure: 0 if it was unable to + * allocate any memory, MAP_FAILED if it was possible to allocate the + * required memory but failed to mmap it to user space, in which case the + * allocated memory is freed anyhow. + * + */ + +#define rtai_malloc(name, size) \ + _rt_shm_alloc(0, name, size, USE_VMALLOC, 0) // legacy + +/** + * Allocate a chunk of memory to be shared inter-intra kernel modules and Linux + * processes. + * + * rt_shm_alloc_adr is used to allocate in user space. + * + * @param start_address is a user desired address where the allocated memory + * should be mapped in user space; + * + * @param name is an unsigned long identifier; + * + * @param size is the amount of required shared memory. + * + * @param suprt is the kernel allocation method to be used, it can be: + * - USE_VMALLOC, use vmalloc; + * - USE_GFP_KERNEL, use kmalloc with GFP_KERNEL; + * - USE_GFP_ATOMIC, use kmalloc with GFP_ATOMIC; + * - USE_GFP_DMA, use kmalloc with GFP_DMA. + * + * Since @c name can be a clumsy identifier, services are provided to + * convert 6 characters identifiers to unsigned long, and vice versa. + * + * @see the functions nam2num() and num2nam(). + * + * It must be remarked that only the very first call does a real allocation, + * any subsequent call to allocate with the same name from anywhere will just + * increase the usage count and map the area to user space, or return the + * related pointer to the already allocated space in kernel space. The function + * returns a pointer to the allocated memory, appropriately mapped to the memory + * space in use. So if one is really sure that the named shared memory has been + * allocated already parameters size and suprt are not used and can be + * assigned any value. + * + * @note If the same process calls rtai_malloc_adr and rtai_malloc() twice in + * the same process it get a zero return value on the second call. + * + * @returns a valid address on succes, on failure: 0 if it was unable to + * allocate any memory, MAP_FAILED if it was possible to allocate the + * required memory but failed to mmap it to user space, in which case the + * allocated memory is freed anyhow. + * + */ + +#define rt_shm_alloc_adr(start_address, name, size, suprt) \ + _rt_shm_alloc(start_address, name, size, suprt, 0) + +#define rt_heap_open_adr(start, name, size, suprt) \ + _rt_shm_alloc(start, name, size, suprt, 1) + +/** + * Allocate a chunk of memory to be shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rtai_malloc_adr is used to allocate shared memory from user space. + * + * @param start_address is the adr were the shared memory should be mapped. + * + * @param name is an unsigned long identifier; + * + * @param size is the amount of required shared memory; + * + * rtai_malloc_adr is a legacy helper macro, the real job is carried out by a + * call to rt_shm_alloc_adr() with the same name, size and with vmalloc support. + * This function should not be used in newly developed applications. See + * rt_shm_alloc_adr for more details. + * + * @returns a valid address on succes, 0 on failure. + * + */ + +#define rtai_malloc_adr(start_address, name, size) \ + _rt_shm_alloc(start_address, name, size, USE_VMALLOC, 0) // legacy + +RTAI_PROTO(int, rt_shm_free, (unsigned long name)) +{ + int hook, size; + struct { void *nameadr; } arg = { &name }; + if ((hook = open(RTAI_SHM_DEV, O_RDWR)) <= 0) { + return 0; + } +// no SHM_FREE needed, we release it all and munmap will do it through +// the vma close operation provided by shm.c +#ifdef SHM_USE_LXRT + if ((size = rtai_lxrt(BIDX, SIZARG, SHM_SIZE, &arg).i[LOW])) { +#else + if ((size = ioctl(hook, SHM_SIZE, (unsigned long)&arg))) { +#endif + if (munmap((void *)name, size)) { + size = 0; + } + } + close(hook); + return size; +} + +/** + * Free a chunk of shared memory being shared inter-intra + * kernel modules and Linux processes. + * + * rtai_free is used to free a shared memory chunk from user space. + * + * @param name is the unsigned long identifier used when the memory was + * allocated; + * + * @param adr is not used. + * + * rtai_free is a legacy helper macro, the real job is carried out by a + * call to rt_shm_free with the same name. This function should not be used + * in newly developed applications. See rt_shm_alloc_adr for more details. + * + * @returns the size of the succesfully freed memory, 0 on failure. + * + */ + +#define rtai_free(name, adr) \ + rt_shm_free(name) // legacy + +RTAI_PROTO(void *, rt_halloc, (int size)) +{ + struct { long size; } arg = { size }; + return rtai_lxrt(BIDX, SIZARG, HEAP_ALLOC, &arg).v[LOW]; +} + +RTAI_PROTO(void, rt_hfree, (void *addr)) +{ + struct { void *addr; } arg = { addr }; + rtai_lxrt(BIDX, SIZARG, HEAP_FREE, &arg); +} + +RTAI_PROTO(void *, rt_named_halloc, (unsigned long name, int size)) +{ + struct { unsigned long name; long size; } arg = { name, size }; + return rtai_lxrt(BIDX, SIZARG, HEAP_NAMED_ALLOC, &arg).v[LOW]; +} + +RTAI_PROTO(void, rt_named_hfree, (void *addr)) +{ + struct { void *addr; } arg = { addr }; + rtai_lxrt(BIDX, SIZARG, HEAP_NAMED_FREE, &arg); +} + +RTAI_PROTO(void *, rt_malloc, (int size)) +{ + struct { long size; } arg = { size }; + return rtai_lxrt(BIDX, SIZARG, MALLOC, &arg).v[LOW]; +} + +RTAI_PROTO(void, rt_free, (void *addr)) +{ + struct { void *addr; } arg = { addr }; + rtai_lxrt(BIDX, SIZARG, FREE, &arg); +} + +RTAI_PROTO(void *, rt_named_malloc, (unsigned long name, int size)) +{ + struct { unsigned long name; long size; } arg = { name, size }; + return rtai_lxrt(BIDX, SIZARG, NAMED_MALLOC, &arg).v[LOW]; +} + +RTAI_PROTO(void, rt_named_free, (void *addr)) +{ + struct { void *addr; } arg = { addr }; + rtai_lxrt(BIDX, SIZARG, NAMED_FREE, &arg); +} + +#endif /* __KERNEL__ */ + +/** + * Close a real time group heap being shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rt_heap_close is used to close a previously opened real time group heap. + * + * @param name is the unsigned long identifier used to identify the heap. + * + * @param adr is not used. + * + * Analogously to what done by any allocation function this group real time + * heap closing call have just the effect of decrementing a usage count, + * unmapping any user space heap being closed, till the last is done, as that + * is the one the really closes the group heap, freeing any allocated memory. + * + * @returns the size of the succesfully freed heap, 0 on failure. + * + */ + +#define rt_heap_close(name, adr) rt_shm_free(name) + +// aliases in use already, different heads different choices +#define rt_heap_init rt_heap_open +#define rt_heap_create rt_heap_open +#define rt_heap_acquire rt_heap_open +#define rt_heap_init_adr rt_heap_open_adr +#define rt_heap_create_adr rt_heap_open_adr +#define rt_heap_acquire_adr rt_heap_open_adr + +#define rt_heap_delete rt_heap_close +#define rt_heap_destroy rt_heap_close +#define rt_heap_release rt_heap_close + +// these have no aliases, and never will + +/** + * Open the global real time heap to be shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rt_global_heap_open is used to open the global real time heap. + * + * The global heap is created by the shared memory module and its opening is + * needed in user space to map it to the process address space. In kernel + * space opening the global heap in a task is not required but should be done + * anyhow, both for symmetry and to register its usage. + * + */ + +#define rt_global_heap_open() rt_heap_open(GLOBAL_HEAP_ID, 0, 0) + +/** + * Close the global real time heap being shared inter-intra kernel modules and + * Linux processes. + * + * @internal + * + * rt_global_heap_close is used to close the global real time heap. + * + * Closing a global heap in user space has just the effect of deregistering + * its use and unmapping the related memory from a process address space. + * In kernel tasks just the deregistration is performed. + * The global real time heap is destroyed just a the rmmoding of the shared + * memory module. + * + */ + +#define rt_global_heap_close() rt_heap_close(GLOBAL_HEAP_ID, 0) + +/*@}*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_RTAI_SHM_H */ diff --git a/include/rtai_signal.h b/include/rtai_signal.h new file mode 100644 index 0000000..a65fa72 --- /dev/null +++ b/include/rtai_signal.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2006 Paolo Mantegazza + * + * 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, see . + * + * + */ + +#ifndef _RTAI_SIGNAL_H_ +#define _RTAI_SIGNAL_H_ + +#define RTAI_SIGNALS_IDX BIDX + +#include + +#define MAXSIGNALS 16 + +#define SIGNAL_TASK_INIPRIO 0 + +struct rt_signal_t { unsigned long flags; RT_TASK *sigtask; }; + +struct sigsuprt_t { RT_TASK *sigtask; RT_TASK *task; long signal; void (*sighdl)(long, RT_TASK *); unsigned long cpuid; }; + +#ifdef __KERNEL__ + +#define SIGNAL_ENBIT 0 +#define SIGNAL_PNDBIT 1 + +#define SIGNAL_TASK_STACK_SIZE 8192 + +RTAI_SYSCALL_MODE int rt_signal_helper(RT_TASK *task); + +int rt_request_signal(long signal, void (*sighdl)(long, RT_TASK *)); + +RTAI_SYSCALL_MODE int rt_request_signal_(RT_TASK *sigtask, RT_TASK *task, long signal); + +RTAI_SYSCALL_MODE int rt_release_signal(long signal, RT_TASK *task); + +RTAI_SYSCALL_MODE void rt_enable_signal(long signal, RT_TASK *task); + +RTAI_SYSCALL_MODE void rt_disable_signal(long signal, RT_TASK *task); + +RTAI_SYSCALL_MODE void rt_trigger_signal(long signal, RT_TASK *task); + +RTAI_SYSCALL_MODE int rt_wait_signal(RT_TASK *sigtask, RT_TASK *task); + +#else /* !__KERNEL__ */ + +#include + +#include + +#define SIGNAL_TASK_STACK_SIZE 64*1024 + +#ifndef __SIGNAL_SUPPORT_FUN__ +#define __SIGNAL_SUPPORT_FUN__ + +static void signal_suprt_fun(struct sigsuprt_t *funarg) +{ + struct sigtsk_t { RT_TASK *sigtask; RT_TASK *task; }; + struct sigreq_t { RT_TASK *sigtask; RT_TASK *task; long signal; void (*sighdl)(int, RT_TASK *); }; + struct sigsuprt_t arg = *funarg; + + if ((arg.sigtask = rt_thread_init(rt_get_name(0), SIGNAL_TASK_INIPRIO, 0, SCHED_FIFO, 1 << arg.cpuid))) { + if (!rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(struct sigreq_t), RT_SIGNAL_REQUEST, &arg).i[LOW]) { + rt_grow_and_lock_stack(SIGNAL_TASK_STACK_SIZE/2); + rt_make_hard_real_time(); + while (rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(struct sigtsk_t), RT_SIGNAL_WAITSIG, &arg).i[LOW]) { + arg.sighdl(arg.signal, arg.task); + } + rt_make_soft_real_time(); + } + rt_task_delete(arg.sigtask); + } +} + +#endif /* __SIGNAL_SUPPORT_FUN__ */ + +RTAI_PROTO(int, rt_request_signal, (long signal, void (*sighdl)(long, RT_TASK *))) +{ + if (signal >= 0 && sighdl) { + struct sigsuprt_t arg = { NULL, rt_buddy(), signal, sighdl }; + arg.cpuid = rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(void *), RT_SIGNAL_HELPER, &arg.sigtask).i[LOW]; + if (rt_thread_create((void *)signal_suprt_fun, &arg, SIGNAL_TASK_STACK_SIZE)) { + return rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(RT_TASK *), RT_SIGNAL_HELPER, &arg.task).i[LOW]; + } + } + return -EINVAL; +} + +RTAI_PROTO(int, rt_release_signal, (long signal, RT_TASK *task)) +{ + struct { long signal; RT_TASK *task; } arg = { signal, task }; + return rtai_lxrt(RTAI_SIGNALS_IDX, SIZARG, RT_SIGNAL_RELEASE, &arg).i[LOW]; +} + +RTAI_PROTO(void, rt_enable_signal, (long signal, RT_TASK *task)) +{ + struct { long signal; RT_TASK *task; } arg = { signal, task }; + rtai_lxrt(RTAI_SIGNALS_IDX, SIZARG, RT_SIGNAL_ENABLE, &arg); +} + +RTAI_PROTO(void, rt_disable_signal, (long signal, RT_TASK *task)) +{ + struct { long signal; RT_TASK *task; } arg = { signal, task }; + rtai_lxrt(RTAI_SIGNALS_IDX, SIZARG, RT_SIGNAL_DISABLE, &arg); +} + +RTAI_PROTO(void, rt_trigger_signal, (long signal, RT_TASK *task)) +{ + struct { long signal; RT_TASK *task; } arg = { signal, task }; + rtai_lxrt(RTAI_SIGNALS_IDX, SIZARG, RT_SIGNAL_TRIGGER, &arg); +} + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_SIGNAL_H_ */ diff --git a/include/rtai_spl.h b/include/rtai_spl.h new file mode 100644 index 0000000..a8500da --- /dev/null +++ b/include/rtai_spl.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2002,2003 Paolo Mantegazza + * + * 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, see . + * + */ + +#ifndef _RTAI_SPL_H +#define _RTAI_SPL_H + +#include + +struct rtai_spl; + +#ifdef __KERNEL__ + +#ifndef __cplusplus + +typedef struct rtai_spl { + void *owndby; + int count; + unsigned long flags; +} SPL; + +#else /* __cplusplus */ +extern "C" { +#endif /* !__cplusplus */ + +RTAI_SYSCALL_MODE int rt_spl_init(struct rtai_spl *spl); + +RTAI_SYSCALL_MODE int rt_spl_delete(struct rtai_spl *spl); + +RTAI_SYSCALL_MODE SPL *_rt_named_spl_init(unsigned long spl_name); + +RTAI_SYSCALL_MODE int rt_named_spl_delete(SPL *spl); + +RTAI_SYSCALL_MODE int rt_spl_lock(struct rtai_spl *spl); + +RTAI_SYSCALL_MODE int rt_spl_lock_if(struct rtai_spl *spl); + +RTAI_SYSCALL_MODE int rt_spl_lock_timed(struct rtai_spl *spl, + unsigned long ns); + +RTAI_SYSCALL_MODE int rt_spl_unlock(struct rtai_spl *spl); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* !__KERNEL__ */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +RTAI_PROTO(struct rtai_spl *, rt_spl_init,(unsigned long name)) +{ + struct { unsigned long name; } arg = { name }; + return (struct rtai_spl *)rtai_lxrt(BIDX, SIZARG, LXRT_SPL_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_spl_delete,(struct rtai_spl *spl)) +{ + struct { struct rtai_spl *spl; } arg = { spl }; + return rtai_lxrt(BIDX, SIZARG, LXRT_SPL_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(struct rtai_spl *, rt_named_spl_init,(const char *name)) +{ + struct { unsigned long name; } arg = { nam2num(name) }; + return (struct rtai_spl *)rtai_lxrt(BIDX, SIZARG, NAMED_SPL_INIT, &arg).v[LOW]; +} + +RTAI_PROTO(int, rt_named_spl_delete,(struct rtai_spl *spl)) +{ + struct { struct rtai_spl *spl; } arg = { spl }; + return rtai_lxrt(BIDX, SIZARG, NAMED_SPL_DELETE, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_spl_lock,(struct rtai_spl *spl)) +{ + struct { struct rtai_spl *spl; } arg = { spl }; + return rtai_lxrt(BIDX, SIZARG, SPL_LOCK, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_spl_lock_if,(struct rtai_spl *spl)) +{ + struct { struct rtai_spl *spl; } arg = { spl }; + return rtai_lxrt(BIDX, SIZARG, SPL_LOCK_IF, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_spl_lock_timed,(struct rtai_spl *spl, RTIME delay)) +{ + struct { struct rtai_spl *spl; RTIME delay; } arg = { spl, delay }; + return rtai_lxrt(BIDX, SIZARG, SPL_LOCK_TIMED, &arg).i[LOW]; +} + +RTAI_PROTO(int, rt_spl_unlock,(struct rtai_spl *spl)) +{ + struct { struct rtai_spl *spl; } arg = { spl }; + return rtai_lxrt(BIDX, SIZARG, SPL_UNLOCK, &arg).i[LOW]; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KERNEL__ */ + +#if !defined(__KERNEL__) || defined(__cplusplus) + +typedef struct rtai_spl { + int opaque; +} SPL; + +#endif /* !__KERNEL__ || __cplusplus */ + +#endif /* !_RTAI_SPL_H */ diff --git a/include/rtai_taskq.h b/include/rtai_taskq.h new file mode 100644 index 0000000..fb35def --- /dev/null +++ b/include/rtai_taskq.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2010 Paolo Mantegazza + * + * 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, see . + * + */ + + +#ifndef _RTAI_TASKQ_H +#define _RTAI_TASKQ_H + +#include + +extern struct epoch_struct boot_epoch; + +typedef struct rt_task_queue { + struct rt_queue queue; /* <= Must be first in struct. */ + int qtype; + unsigned long status; +} TASKQ; + +#define XNTIMEO 0x00000001 // RTE_TIMOUT +#define XNRMID 0x00000002 // RTE_OBJREM +#define XNBREAK 0x00000004 // RTE_UNBLKD + +#define TASKQ_PRIO 0x0 +#define TASKQ_FIFO 0x1 + +#define RT_SCHED_TASKQ RT_SCHED_SEMAPHORE + +#ifdef CONFIG_SMP + +extern volatile unsigned long tosched_mask; + +#define TOSCHED_TASK(task) \ + do { tosched_mask |= (1 << (task)->runnable_on_cpus); } while (0) + +#else /* !CONFIG_SMP */ + +#define TOSCHED_TASK(task) + +#endif /* CONFIG_SMP */ + +void rt_schedule_readied(void); + +void rt_taskq_init(TASKQ *taskq, unsigned int type); + +RT_TASK *rt_taskq_ready_one(TASKQ *taskq); + +int rt_taskq_ready_all(TASKQ *taskq, unsigned long why); + +void rt_taskq_wait(TASKQ *taskq); + +void rt_taskq_wait_until(TASKQ *taskq, RTIME time); + +#define rt_taskq_delete(taskq) rt_taskq_ready_all(taskq, RTE_OBJREM) + +#define rt_taskq_wait_timed(taskq, delay) \ + do { rt_taskq_wait_until(taskq, get_time() + delay); } while (0) + +static inline int rt_task_test_taskq_retval(RT_TASK *task, unsigned long mask) +{ + return ((task)->retval & mask); +} + +#endif /* !_RTAI_TASKQ_H */ diff --git a/include/rtai_trace.h b/include/rtai_trace.h new file mode 100644 index 0000000..926fe84 --- /dev/null +++ b/include/rtai_trace.h @@ -0,0 +1,513 @@ +/* + * This file contains the necessary definitions for the RTAI tracer. + * + * Copyright (C) 2000, Karim Yaghmour + * + * 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, see . + * + */ + +#ifndef _RTAI_TRACE_H +#define _RTAI_TRACE_H + +#include + +#if defined(CONFIG_RTAI_TRACE) && defined(__KERNEL__) + +#include + +/* Is RTAI tracing enabled */ + +/* The functions to the tracer management code */ +int rt_register_tracer + (tracer_call /* The tracer function */); +int rt_unregister_tracer + (tracer_call /* The tracer function */); +int rt_trace_event + (uint8_t /* Event ID (as defined in this header file) */, + void* /* Structure describing the event */); + +/* Generic macros */ +#define RT_TRACE_EVENT(ID, DATA) rt_trace_event(ID, DATA) + +#define TRACE_RTAI_START TRACE_EV_MAX + +/* Traced events */ +#define TRACE_RTAI_EV_MOUNT TRACE_RTAI_START + 1 /* The RTAI subsystem was mounted */ +#define TRACE_RTAI_EV_UMOUNT TRACE_RTAI_START + 2 /* The RTAI subsystem was unmounted */ +#define TRACE_RTAI_EV_GLOBAL_IRQ_ENTRY TRACE_RTAI_START + 3 /* Entry in a global IRQ */ +#define TRACE_RTAI_EV_GLOBAL_IRQ_EXIT TRACE_RTAI_START + 4 /* Exit from a global IRQ */ +#define TRACE_RTAI_EV_OWN_IRQ_ENTRY TRACE_RTAI_START + 5 /* Entry in a CPU own IRQ */ +#define TRACE_RTAI_EV_OWN_IRQ_EXIT TRACE_RTAI_START + 6 /* Exit from a CPU own IRQ */ +#define TRACE_RTAI_EV_TRAP_ENTRY TRACE_RTAI_START + 7 /* Entry in a trap */ +#define TRACE_RTAI_EV_TRAP_EXIT TRACE_RTAI_START + 8 /* Exit from a trap */ +#define TRACE_RTAI_EV_SRQ_ENTRY TRACE_RTAI_START + 9 /* Entry in a SRQ */ +#define TRACE_RTAI_EV_SRQ_EXIT TRACE_RTAI_START + 10 /* Exit from a SRQ */ +#define TRACE_RTAI_EV_SWITCHTO_LINUX TRACE_RTAI_START + 11 /* Switch a CPU to Linux */ +#define TRACE_RTAI_EV_SWITCHTO_RT TRACE_RTAI_START + 12 /* Switch a CPU to real-time */ +#define TRACE_RTAI_EV_SCHED_CHANGE TRACE_RTAI_START + 13 /* A scheduling change has occured */ +#define TRACE_RTAI_EV_TASK TRACE_RTAI_START + 14 /* Hit key part of task services */ +#define TRACE_RTAI_EV_TIMER TRACE_RTAI_START + 15 /* Hit key part of timer services */ +#define TRACE_RTAI_EV_SEM TRACE_RTAI_START + 16 /* Hit key part of semaphore services */ +#define TRACE_RTAI_EV_MSG TRACE_RTAI_START + 17 /* Hit key part of message services */ +#define TRACE_RTAI_EV_RPC TRACE_RTAI_START + 18 /* Hit key part of RPC services */ +#define TRACE_RTAI_EV_MBX TRACE_RTAI_START + 19 /* Hit key part of mail box services */ +#define TRACE_RTAI_EV_FIFO TRACE_RTAI_START + 20 /* Hit key part of FIFO services */ +#define TRACE_RTAI_EV_SHM TRACE_RTAI_START + 21 /* Hit key part of shared memory services */ +#define TRACE_RTAI_EV_LXRT TRACE_RTAI_START + 22 /* Hit key part of LXRT services */ +#define TRACE_RTAI_EV_LXRTI TRACE_RTAI_START + 23 /* Hit key part of LXRT-Informed services */ + +/* Max number of traced events */ +#define TRACE_RTAI_EV_MAX TRACE_RTAI_EV_LXRTI + +/* Structures and macros for traced events */ +/* TRACE_RTAI_MOUNT */ +#define TRACE_RTAI_MOUNT() rt_trace_event(TRACE_RTAI_EV_MOUNT, NULL) + +/* TRACE_RTAI_UMOUNT */ +#define TRACE_RTAI_UMOUNT() rt_trace_event(TRACE_RTAI_EV_UMOUNT, NULL) + +/* TRACE_RTAI_GLOBAL_IRQ_ENTRY */ +typedef struct _trace_rtai_global_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_global_irq_entry; +#define TRACE_RTAI_GLOBAL_IRQ_ENTRY(ID, __dummy) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_global_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + irq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_GLOBAL_IRQ_ENTRY, &irq_entry);\ + } while(0) + +/* TRACE_RTAI_GLOBAL_IRQ_EXIT */ +#define TRACE_RTAI_GLOBAL_IRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_GLOBAL_IRQ_EXIT, NULL) + +/* TRACE_RTAI_OWN_IRQ_ENTRY */ +typedef struct _trace_rtai_own_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_own_irq_entry; +#define TRACE_RTAI_OWN_IRQ_ENTRY(ID) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_own_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + irq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_OWN_IRQ_ENTRY, &irq_entry);\ + } while(0) + +/* TRACE_RTAI_OWN_IRQ_EXIT */ +#define TRACE_RTAI_OWN_IRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_OWN_IRQ_EXIT, NULL) + +/* TRACE_RTAI_TRAP_ENTRY */ +typedef struct _trace_rtai_trap_entry +{ + uint8_t trap_id; /* Trap number */ + uint32_t address; /* Address where trap occured */ +} LTT_PACKED_STRUCT trace_rtai_trap_entry; +#define TRACE_RTAI_TRAP_ENTRY(ID,ADDR) \ + do \ + {\ + trace_rtai_trap_entry trap_event;\ + trap_event.trap_id = ID;\ + trap_event.address = ADDR; \ + rt_trace_event(TRACE_RTAI_EV_TRAP_ENTRY, &trap_event);\ + } while(0) +/* + uint32_t eip; \ + __asm__ __volatile__("pushl %%ip; pop %0": "=g" (eip)); \ + trap_event.address = eip;\ +*/ + +/* TRACE_RTAI_TRAP_EXIT */ +#define TRACE_RTAI_TRAP_EXIT() rt_trace_event(TRACE_RTAI_EV_TRAP_EXIT, NULL) + +/* TRACE_RTAI_SRQ_ENTRY */ +typedef struct _trace_rtai_srq_entry +{ + uint8_t srq_id; /* SRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_srq_entry; +#define TRACE_RTAI_SRQ_ENTRY(ID) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_srq_entry srq_entry;\ + srq_entry.srq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + srq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_SRQ_ENTRY, &srq_entry);\ + } while(0) + +/* TRACE_RTAI_SRQ_EXIT */ +#define TRACE_RTAI_SRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_SRQ_EXIT, NULL) + +/* TRACE_RTAI_SWITCHTO_LINUX */ +typedef struct _trace_rtai_switchto_linux +{ + uint8_t cpu_id; /* The CPUID being switched to Linux */ +} LTT_PACKED_STRUCT trace_rtai_switchto_linux; +#define TRACE_RTAI_SWITCHTO_LINUX(ID) \ + do \ + {\ + trace_rtai_switchto_linux switch_event; \ + switch_event.cpu_id = (uint8_t) ID; \ + rt_trace_event(TRACE_RTAI_EV_SWITCHTO_LINUX, &switch_event); \ + } while(0) + +/* TRACE_RTAI_SWITCHTO_RT */ +typedef struct _trace_rtai_switchto_rt +{ + uint8_t cpu_id; /* The CPUID being switched to RT */ +} LTT_PACKED_STRUCT trace_rtai_switchto_rt; +#define TRACE_RTAI_SWITCHTO_RT(ID) \ + do \ + {\ + trace_rtai_switchto_rt switch_event; \ + switch_event.cpu_id = (uint8_t) ID; \ + rt_trace_event(TRACE_RTAI_EV_SWITCHTO_RT, &switch_event); \ + } while(0) + +/* TRACE_RTAI_SCHED_CHANGE */ +typedef struct _trace_rtai_sched_change +{ + uint32_t out; /* Outgoing process */ + uint32_t in; /* Incoming process */ + uint32_t out_state; /* Outgoing process' state */ +} LTT_PACKED_STRUCT trace_rtai_sched_change; +#define TRACE_RTAI_SCHED_CHANGE(OUT, IN, OUT_STATE) \ + do \ + {\ + trace_rtai_sched_change sched_event;\ + sched_event.out = (uint32_t) OUT;\ + sched_event.in = (uint32_t) IN;\ + sched_event.out_state = (uint32_t) OUT_STATE; \ + rt_trace_event(TRACE_RTAI_EV_SCHED_CHANGE, &sched_event);\ + } while(0) + +/* TRACE_RTAI_TASK */ +#define TRACE_RTAI_EV_TASK_INIT 1 /* Initialize task */ +#define TRACE_RTAI_EV_TASK_DELETE 2 /* Delete task */ +#define TRACE_RTAI_EV_TASK_SIG_HANDLER 3 /* Set signal handler */ +#define TRACE_RTAI_EV_TASK_YIELD 4 /* Yield CPU control */ +#define TRACE_RTAI_EV_TASK_SUSPEND 5 /* Suspend task */ +#define TRACE_RTAI_EV_TASK_RESUME 6 /* Resume task */ +#define TRACE_RTAI_EV_TASK_MAKE_PERIOD_RELATIVE 7 /* Make task periodic relative in nanoseconds */ +#define TRACE_RTAI_EV_TASK_MAKE_PERIOD 8 /* Make task periodic */ +#define TRACE_RTAI_EV_TASK_WAIT_PERIOD 9 /* Wait until the next period */ +#define TRACE_RTAI_EV_TASK_BUSY_SLEEP 10 /* Busy sleep */ +#define TRACE_RTAI_EV_TASK_SLEEP 11 /* Sleep */ +#define TRACE_RTAI_EV_TASK_SLEEP_UNTIL 12 /* Sleep until */ +typedef struct _trace_rtai_task +{ + uint8_t event_sub_id; /* Task event ID */ + uint32_t event_data1; /* Event data */ + uint64_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_task; +#define TRACE_RTAI_TASK(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_task task_event;\ + task_event.event_sub_id = (uint8_t) ID;\ + task_event.event_data1 = (uint32_t) DATA1; \ + task_event.event_data2 = (uint64_t) DATA2; \ + task_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_TASK, &task_event);\ + } while(0) + +/* TRACE_RTAI_TIMER */ +#define TRACE_RTAI_EV_TIMER_REQUEST 1 /* Request timer */ +#define TRACE_RTAI_EV_TIMER_FREE 2 /* Free timer */ +#define TRACE_RTAI_EV_TIMER_REQUEST_APIC 3 /* Request APIC timers */ +#define TRACE_RTAI_EV_TIMER_APIC_FREE 4 /* Free APIC timers */ +#define TRACE_RTAI_EV_TIMER_HANDLE_EXPIRY 5 /* Handle timer expiry */ +typedef struct _trace_rtai_timer +{ + uint8_t event_sub_id; /* Timer event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_timer; +#define TRACE_RTAI_TIMER(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_timer timer_event; \ + timer_event.event_sub_id = (uint8_t) ID; \ + timer_event.event_data1 = (uint32_t) DATA1; \ + timer_event.event_data2 = (uint32_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_TIMER, &timer_event); \ + } while(0) + +/* TRACE_RTAI_SEM */ +#define TRACE_RTAI_EV_SEM_INIT 1 /* Initialize semaphore */ +#define TRACE_RTAI_EV_SEM_DELETE 2 /* Delete semaphore */ +#define TRACE_RTAI_EV_SEM_SIGNAL 3 /* Signal semaphore */ +#define TRACE_RTAI_EV_SEM_WAIT 4 /* Wait on semaphore */ +#define TRACE_RTAI_EV_SEM_WAIT_IF 5 /* Take semaphore if possible */ +#define TRACE_RTAI_EV_SEM_WAIT_UNTIL 6 /* Wait on semaphore until a certain time */ +typedef struct _trace_rtai_sem +{ + uint8_t event_sub_id; /* Semaphore event ID */ + uint32_t event_data1; /* Event data 1 */ + uint64_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_sem; +#define TRACE_RTAI_SEM(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_sem sem_event; \ + sem_event.event_sub_id = (uint8_t) ID; \ + sem_event.event_data1 = (uint32_t) DATA1; \ + sem_event.event_data2 = (uint64_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_SEM, &sem_event); \ + } while(0) + +/* TRACE_RTAI_MSG */ +#define TRACE_RTAI_EV_MSG_SEND 1 /* Send a message */ +#define TRACE_RTAI_EV_MSG_SEND_IF 2 /* Send if possible */ +#define TRACE_RTAI_EV_MSG_SEND_UNTIL 3 /* Try sending until a certain time */ +#define TRACE_RTAI_EV_MSG_RECV 4 /* Receive a message */ +#define TRACE_RTAI_EV_MSG_RECV_IF 5 /* Receive if possible */ +#define TRACE_RTAI_EV_MSG_RECV_UNTIL 6 /* Try receiving until a certain time */ +typedef struct _trace_rtai_msg +{ + uint8_t event_sub_id; /* Message event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_msg; +#define TRACE_RTAI_MSG(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_msg msg_event; \ + msg_event.event_sub_id = (uint8_t) ID; \ + msg_event.event_data1 = (uint32_t) DATA1; \ + msg_event.event_data2 = (uint32_t) DATA2; \ + msg_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_MSG, &msg_event); \ + } while(0) + +/* TRACE_RTAI_RPC */ +#define TRACE_RTAI_EV_RPC_MAKE 1 /* Make a remote procedure call */ +#define TRACE_RTAI_EV_RPC_MAKE_IF 2 /* Make RPC if receiver is ready */ +#define TRACE_RTAI_EV_RPC_MAKE_UNTIL 3 /* Try making an RPC until a certain time */ +#define TRACE_RTAI_EV_RPC_RETURN 4 /* Send result of RPC back to caller */ +typedef struct _trace_rtai_rpc +{ + uint8_t event_sub_id; /* RPC event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_rpc; +#define TRACE_RTAI_RPC(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_rpc rpc_event; \ + rpc_event.event_sub_id = (uint8_t) ID; \ + rpc_event.event_data1 = (uint32_t) DATA1; \ + rpc_event.event_data2 = (uint32_t) DATA2; \ + rpc_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_RPC, &rpc_event); \ + } while(0) + +/* TRACE_RTAI_MBX */ +#define TRACE_RTAI_EV_MBX_INIT 1 /* Initialize Message BoX */ +#define TRACE_RTAI_EV_MBX_DELETE 2 /* Delete message box */ +#define TRACE_RTAI_EV_MBX_SEND 3 /* Send a message to a message box */ +#define TRACE_RTAI_EV_MBX_SEND_WP 4 /* Send as many bytes as possible */ +#define TRACE_RTAI_EV_MBX_SEND_IF 5 /* Send a message if possible */ +#define TRACE_RTAI_EV_MBX_SEND_UNTIL 6 /* Try sending until a certain time */ +#define TRACE_RTAI_EV_MBX_RECV 7 /* Receive a message */ +#define TRACE_RTAI_EV_MBX_RECV_WP 8 /* Receive as many bytes as possible */ +#define TRACE_RTAI_EV_MBX_RECV_IF 9 /* Receive a message if available */ +#define TRACE_RTAI_EV_MBX_RECV_UNTIL 10 /* Try receiving until a certain time */ +typedef struct _trace_rtai_mbx +{ + uint8_t event_sub_id; /* Message Box event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_mbx; +#define TRACE_RTAI_MBX(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_mbx mbx_event; \ + mbx_event.event_sub_id = (uint8_t) ID; \ + mbx_event.event_data1 = (uint32_t) DATA1; \ + mbx_event.event_data2 = (uint32_t) DATA2; \ + mbx_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_MBX, &mbx_event); \ + } while(0) + +/* TRACE_RTAI_FIFO */ +#define TRACE_RTAI_EV_FIFO_CREATE 1 /* Create FIFO */ +#define TRACE_RTAI_EV_FIFO_DESTROY 2 /* Destroy FIFO */ +#define TRACE_RTAI_EV_FIFO_RESET 3 /* Reset FIFO */ +#define TRACE_RTAI_EV_FIFO_RESIZE 4 /* Resize FIFO */ +#define TRACE_RTAI_EV_FIFO_PUT 5 /* Write data to FIFO */ +#define TRACE_RTAI_EV_FIFO_GET 6 /* Get data from FIFO */ +#define TRACE_RTAI_EV_FIFO_CREATE_HANDLER 7 /* Install FIFO handler */ +#define TRACE_RTAI_EV_FIFO_OPEN 8 /* Open FIFO */ +#define TRACE_RTAI_EV_FIFO_RELEASE 9 /* Release FIFO */ +#define TRACE_RTAI_EV_FIFO_READ 10 /* Read from FIFO */ +#define TRACE_RTAI_EV_FIFO_WRITE 11 /* Write to FIFO */ +#define TRACE_RTAI_EV_FIFO_READ_TIMED 12 /* Read with time limit */ +#define TRACE_RTAI_EV_FIFO_WRITE_TIMED 13 /* Write with time limit */ +#define TRACE_RTAI_EV_FIFO_READ_ALLATONCE 14 /* Read all the data from FIFO */ +#define TRACE_RTAI_EV_FIFO_LLSEEK 15 /* Seek position into FIFO */ +#define TRACE_RTAI_EV_FIFO_FASYNC 16 /* Asynchronous notification */ +#define TRACE_RTAI_EV_FIFO_IOCTL 17 /* IO control on FIFO */ +#define TRACE_RTAI_EV_FIFO_POLL 18 /* Poll FIFO */ +#define TRACE_RTAI_EV_FIFO_SUSPEND_TIMED 19 /* Suspend task for given period */ +#define TRACE_RTAI_EV_FIFO_SET_ASYNC_SIG 20 /* Set asynchrounous signal */ +#define TRACE_RTAI_EV_FIFO_SEM_INIT 21 /* Initialize semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_POST 22 /* Post semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_WAIT 23 /* Wait on semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_TRY_WAIT 24 /* Try waiting on semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_TIMED_WAIT 25 /* Wait on semaphore until a certain time */ +#define TRACE_RTAI_EV_FIFO_SEM_DESTROY 26 /* Destroy semaphore */ +typedef struct _trace_rtai_fifo +{ + uint8_t event_sub_id; /* FIFO event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_fifo; +#define TRACE_RTAI_FIFO(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_fifo fifo_event; \ + fifo_event.event_sub_id = (uint8_t) ID; \ + fifo_event.event_data1 = (uint32_t) DATA1; \ + fifo_event.event_data2 = (uint32_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_FIFO, &fifo_event); \ + } while(0) + +/* TRACE_RTAI_SHM */ +#define TRACE_RTAI_EV_SHM_MALLOC 1 /* Allocate shared memory */ +#define TRACE_RTAI_EV_SHM_KMALLOC 2 /* Allocate shared memory in kernel space */ +#define TRACE_RTAI_EV_SHM_GET_SIZE 3 /* Get the size of the shared memory area */ +#define TRACE_RTAI_EV_SHM_FREE 4 /* Free shared memory */ +#define TRACE_RTAI_EV_SHM_KFREE 5 /* Free kernel space shared memory */ +typedef struct _trace_rtai_shm +{ + uint8_t event_sub_id; /* SHared Memory event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint32_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_shm; +#define TRACE_RTAI_SHM(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_shm shm_event; \ + shm_event.event_sub_id = (uint8_t) ID; \ + shm_event.event_data1 = (uint32_t) DATA1; \ + shm_event.event_data2 = (uint32_t) DATA2; \ + shm_event.event_data3 = (uint32_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_SHM, &shm_event); \ + } while(0) + +/* TRACE_RTAI_LXRT */ +#define TRACE_RTAI_EV_LXRT_RTAI_SYSCALL_ENTRY 1 /* Entry in LXRT syscall */ +#define TRACE_RTAI_EV_LXRT_RTAI_SYSCALL_EXIT 2 /* Exit from LXRT syscall */ +#define TRACE_RTAI_EV_LXCHANGE 3 /* Scheduling change */ +#define TRACE_RTAI_EV_LXRT_STEAL_TASK 4 /* Take task control from Linux */ +#define TRACE_RTAI_EV_LXRT_GIVE_BACK_TASK 5 /* Give task control back to Linux */ +#define TRACE_RTAI_EV_LXRT_SUSPEND 6 /* Suspend a task */ +#define TRACE_RTAI_EV_LXRT_RESUME 7 /* Resume task's execution */ +#define TRACE_RTAI_EV_LXRT_HANDLE 8 /* Handle a request for an RTAI service */ +typedef struct _trace_rtai_lxrt +{ + uint8_t event_sub_id; /* LXRT event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint32_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_lxrt; +#define TRACE_RTAI_LXRT(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_lxrt lxrt_event; \ + lxrt_event.event_sub_id = (uint8_t) ID; \ + lxrt_event.event_data1 = (uint32_t) DATA1; \ + lxrt_event.event_data2 = (uint32_t) DATA2; \ + lxrt_event.event_data3 = (uint32_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_LXRT, &lxrt_event); \ + } while(0) + +/* TRACE_RTAI_LXRTI */ +#define TRACE_RTAI_EV_LXRTI_NAME_ATTACH 1 /* Register current process as name */ +#define TRACE_RTAI_EV_LXRTI_NAME_LOCATE 2 /* Locate a given process usint it's name */ +#define TRACE_RTAI_EV_LXRTI_NAME_DETACH 3 /* Detach process from name */ +#define TRACE_RTAI_EV_LXRTI_SEND 4 /* Send message to PID */ +#define TRACE_RTAI_EV_LXRTI_RECV 5 /* Receive message */ +#define TRACE_RTAI_EV_LXRTI_CRECV 6 /* Non-blocking receive */ +#define TRACE_RTAI_EV_LXRTI_REPLY 7 /* Reply to message received */ +#define TRACE_RTAI_EV_LXRTI_PROXY_ATTACH 8 /* Attach proxy to process */ +#define TRACE_RTAI_EV_LXRTI_PROXY_DETACH 9 /* Detach proxy from process */ +#define TRACE_RTAI_EV_LXRTI_TRIGGER 10 /* Trigger proxy */ +typedef struct _trace_rtai_lxrti +{ + uint8_t event_sub_id; /* LXRT event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_lxrti; +#define TRACE_RTAI_LXRTI(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_lxrti lxrti_event; \ + lxrti_event.event_sub_id = (uint8_t) ID; \ + lxrti_event.event_data1 = (uint32_t) DATA1; \ + lxrti_event.event_data2 = (uint32_t) DATA2; \ + lxrti_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_LXRTI, &lxrti_event); \ + } while(0) + +#else /* !(CONFIG_RTAI_TRACE && __KERNEL__) */ +#define RT_TRACE_EVENT(ID, DATA) +#define TRACE_RTAI_MOUNT() +#define TRACE_RTAI_UMOUNT() +#define TRACE_RTAI_GLOBAL_IRQ_ENTRY(ID,X) +#define TRACE_RTAI_GLOBAL_IRQ_EXIT() +#define TRACE_RTAI_OWN_IRQ_ENTRY(ID) +#define TRACE_RTAI_OWN_IRQ_EXIT() +#define TRACE_RTAI_TRAP_ENTRY(ID,ADDR) +#define TRACE_RTAI_TRAP_EXIT() +#define TRACE_RTAI_SRQ_ENTRY(a) +#define TRACE_RTAI_SRQ_EXIT() +#define TRACE_RTAI_SWITCHTO_LINUX(ID) +#define TRACE_RTAI_SWITCHTO_RT(ID) +#define TRACE_RTAI_SCHED_CHANGE(OUT, IN, OUT_STATE) +#define TRACE_RTAI_TASK(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_TIMER(ID, DATA1, DATA2) +#define TRACE_RTAI_SEM(ID, DATA1, DATA2) +#define TRACE_RTAI_MSG(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_RPC(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_MBX(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_FIFO(ID, DATA1, DATA2) +#define TRACE_RTAI_SHM(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_LXRT(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_LXRTI(ID, DATA1, DATA2, DATA3) +#endif /* CONFIG_RTAI_TRACE && __KERNEL__ */ + +#endif /* !_RTAI_TRACE_H */ diff --git a/include/rtai_types.h b/include/rtai_types.h new file mode 100644 index 0000000..5150da8 --- /dev/null +++ b/include/rtai_types.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 1999-2003 Paolo Mantegazza + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_TYPES_H +#define _RTAI_TYPES_H + +#include +#include + +#define PRIO_Q 0 +#define FIFO_Q 4 +#define RES_Q 3 + +#define BIN_SEM 1 +#define CNT_SEM 2 +#define RES_SEM 3 + +#define RESEM_RECURS 1 +#define RESEM_BINSEM 0 +#define RESEM_CHEKWT -1 + +#define RT_SCHED_FIFO 0 +#define RT_SCHED_RR 1 + +#define RTAI_PROTO(type,name,arglist) static inline type name arglist +#define RTAI_PROTO_ALWAYS_INLINE(type,name,arglist) static inline type name arglist + +struct pt_regs; + +struct rt_task_struct; + +typedef long long RTIME; + +typedef int (*RT_TRAP_HANDLER)(int, int, struct pt_regs *,void *); + +struct rt_times { + int linux_tick; + int periodic_tick; + RTIME tick_time; + RTIME linux_time; + RTIME intr_time; +}; + +#endif /* !_RTAI_TYPES_H */ diff --git a/include/rtai_wrappers.h b/include/rtai_wrappers.h new file mode 100644 index 0000000..39bd692 --- /dev/null +++ b/include/rtai_wrappers.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2017 Philippe Gerum + * Copyright (C) 2019 Alec Ari + * + * 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, see . + * + */ + +#ifndef _RTAI_WRAPPERS_H +#define _RTAI_WRAPPERS_H + +#ifdef __KERNEL__ + +#include +#ifndef __cplusplus +#include +#endif /* !__cplusplus */ + +#include + +#define RTAI_MODULE_PARM(name, type) \ + module_param(name, type, 0444) + +#ifndef DEFINE_SPINLOCK +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#endif + +#ifndef DECLARE_MUTEX_LOCKED +#ifndef __DECLARE_SEMAPHORE_GENERIC +#define DECLARE_MUTEX_LOCKED(name) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name, 0) +#else +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) +#endif +#endif + +#ifndef cpu_online_map +#define cpu_online_map (*(cpumask_t *)cpu_online_mask) +#endif + +#ifndef init_MUTEX_LOCKED +#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) +#endif + +#define RTAI_MODULE_PARM_ARRAY(name, type, addr, size) \ + module_param_array(name, type, addr, 0400); + +/* Basic class macros */ + +#include +typedef struct class class_t; +#define CLASS_DEVICE_CREATE(cls, devt, device, fmt, arg...) device_create(cls, NULL, devt, NULL, fmt, ##arg) +#define class_device_destroy(a, b) device_destroy(a, b) + +#define mm_remap_page_range(vma,from,to,size,prot) remap_page_range(vma,from,to,size,prot) + +#define get_tsk_addr_limit(t) ((t)->thread_info->addr_limit.seg) + +#define self_daemonize(name) daemonize(name) + +#define get_thread_ptr(t) ((t)->thread_info) + +#define RTAI_LINUX_IRQ_HANDLED IRQ_HANDLED + +#define CPUMASK_T(name) ((cpumask_t){ { name } }) +#define CPUMASK(name) (name.bits[0]) + +#include + +#define find_task_by_pid(nr) \ + find_task_by_pid_ns(nr, &init_pid_ns) +#define kill_proc(pid, sig, priv) \ + kill_proc_info(sig, (priv) ? SEND_SIG_PRIV : SEND_SIG_NOINFO, pid) + +#endif /* __KERNEL__ */ + +#endif /* !_RTAI_WRAPPERS_H */