#include <stdarg.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <asm/msr.h>
#include <asm/io.h>
#include <linux/cpumask.h>
#include "vsnprintf.h"
#include <rtai.h>
#include <rtai_sched.h>
#if RTAI > 2
#include <rtai_sem.h>
#endif
#include <rtai_shm.h>
#include <rtai_fifos.h>
#include "rtapi.h"
#include <rtapi_mutex.h>
#include "rtapi_common.h"
#ifndef RTAI_NR_TRAPS
#define RTAI_NR_TRAPS HAL_NR_FAULTS
#endif
#if RTAI < 5
#define rt_free_timers rt_free_timer
#endif
static RT_TASK *ostask_array[RTAPI_MAX_TASKS + 1];
static void *shmem_addr_array[RTAPI_MAX_SHMEMS + 1];
static SEM ossem_array[RTAPI_MAX_SEMS + 1];
#define DEFAULT_MAX_DELAY 10000
static long int max_delay = DEFAULT_MAX_DELAY;
static unsigned long timer_counts;
static int msg_level = RTAPI_MSG_ERR;
RTAPI_MP_INT(msg_level, "debug message level (default=1)");
MODULE_AUTHOR("John Kasunich, Fred Proctor, & Paul Corner");
MODULE_DESCRIPTION("Portable Real Time API for RTAI");
MODULE_LICENSE("GPL");
#include "rtapi_proc.h"
static int module_delete(int module_id);
static int task_delete(int task_id);
static int shmem_delete(int shmem_id, int module_id);
static int sem_delete(int sem_id, int module_id);
static int fifo_delete(int fifo_id, int module_id);
static int irq_delete(unsigned int irq_num);
int init_module(void)
{
int n;
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Init\n");
rtapi_data = rtai_kmalloc(RTAPI_KEY, sizeof(rtapi_data_t));
if (rtapi_data == NULL) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: could not open shared memory\n");
return -ENOMEM;
}
init_rtapi_data(rtapi_data);
if (rtapi_data->rev_code != rev_code) {
rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: version mismatch %d vs %d\n", rtapi_data->rev_code, rev_code);
rtai_kfree(RTAPI_KEY);
return -EINVAL;
}
module_array = rtapi_data->module_array;
task_array = rtapi_data->task_array;
shmem_array = rtapi_data->shmem_array;
sem_array = rtapi_data->sem_array;
fifo_array = rtapi_data->fifo_array;
irq_array = rtapi_data->irq_array;
for (n = 0; n <= RTAPI_MAX_TASKS; n++) {
ostask_array[n] = NULL;
}
for (n = 0; n <= RTAPI_MAX_SHMEMS; n++) {
shmem_addr_array[n] = NULL;
}
rtapi_data->timer_running = 0;
rtapi_data->timer_period = 0;
max_delay = DEFAULT_MAX_DELAY;
rt_linux_use_fpu(1);
n = NR_CPUS-1;
while ( ! cpu_online(n) ) {
n--;
}
rtapi_data->rt_cpu = n;
#ifdef RTAPI_USE_PROCFS
if (proc_init() != 0) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: Could not activate /proc entries\n");
proc_clean();
}
#endif
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Init complete\n");
return 0;
}
void cleanup_module(void)
{
int n;
if (rtapi_data == NULL) {
return;
}
rtapi_mutex_get(&(rtapi_data->mutex));
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exiting\n");
for (n = 1; n <= RTAPI_MAX_MODULES; n++) {
if (module_array[n].state == REALTIME) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' (ID: %02d) did not call rtapi_exit()\n",
module_array[n].name, n);
module_delete(n);
}
}
for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
if (irq_array[n].irq_num != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: interrupt handler %02d not deleted (IRQ %d)\n",
n, irq_array[n].irq_num);
irq_delete(irq_array[n].irq_num);
}
}
for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
if (fifo_array[n].state != UNUSED) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: FIFO %02d not deleted\n", n);
}
}
for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
while (sem_array[n].users > 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: semaphore %02d not deleted\n", n);
}
}
for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
if (shmem_array[n].rtusers > 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: shared memory block %02d not deleted\n", n);
}
}
for (n = 1; n <= RTAPI_MAX_TASKS; n++) {
if (task_array[n].state != EMPTY) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERROR: task %02d not deleted\n", n);
rtapi_task_pause(n);
task_delete(n);
}
}
if (rtapi_data->timer_running != 0) {
stop_rt_timer();
rt_free_timers();
rtapi_data->timer_period = 0;
timer_counts = 0;
rtapi_data->timer_running = 0;
max_delay = DEFAULT_MAX_DELAY;
}
rtapi_mutex_give(&(rtapi_data->mutex));
#ifdef RTAPI_USE_PROCFS
proc_clean();
#endif
rtai_kfree(RTAPI_KEY);
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exit complete\n");
return;
}
int rtapi_init(const char *modname)
{
int n, module_id;
module_data *module;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: initing module %s\n", modname);
rtapi_mutex_get(&(rtapi_data->mutex));
n = 1;
while ((n <= RTAPI_MAX_MODULES) && (module_array[n].state != NO_MODULE)) {
n++;
}
if (n > RTAPI_MAX_MODULES) {
rtapi_mutex_give(&(rtapi_data->mutex));
rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: reached module limit %d\n",
n);
return -EMFILE;
}
module_id = n;
module = &(module_array[n]);
module->state = REALTIME;
if (modname != NULL) {
rtapi_snprintf(module->name, RTAPI_NAME_LEN, "%s", modname);
} else {
rtapi_snprintf(module->name, RTAPI_NAME_LEN, "RTMOD%03d", module_id);
}
rtapi_data->rt_module_count++;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module '%s' loaded, ID: %d\n",
module->name, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return module_id;
}
int rtapi_exit(int module_id)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = module_delete(module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int module_delete(int module_id)
{
module_data *module;
char name[RTAPI_NAME_LEN + 1];
int n;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %d exiting\n", module_id);
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
return -EINVAL;
}
module = &(module_array[module_id]);
if (module->state != REALTIME) {
return -EINVAL;
}
for (n = 1; n <= RTAPI_MAX_TASKS; n++) {
if ((task_array[n].state != EMPTY)
&& (task_array[n].owner == module_id)) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' failed to delete task %02d\n",
module->name, n);
task_delete(n);
}
}
for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
if (test_bit(module_id, shmem_array[n].bitmap)) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' failed to delete shmem %02d\n",
module->name, n);
shmem_delete(n, module_id);
}
}
for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
if (test_bit(module_id, sem_array[n].bitmap)) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' failed to delete sem %02d\n",
module->name, n);
sem_delete(n, module_id);
}
}
for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
if ((fifo_array[n].reader == module_id) ||
(fifo_array[n].writer == module_id)) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' failed to delete fifo %02d\n",
module->name, n);
fifo_delete(n, module_id);
}
}
for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
if (irq_array[n].owner == module_id) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: module '%s' failed to delete handler for IRQ %d\n",
module->name, irq_array[n].irq_num);
irq_delete(irq_array[n].irq_num);
}
}
rtapi_snprintf(name, RTAPI_NAME_LEN, "%s", module->name);
module->state = NO_MODULE;
module->name[0] = '\0';
rtapi_data->rt_module_count--;
if (rtapi_data->rt_module_count == 0) {
if (rtapi_data->timer_running != 0) {
stop_rt_timer();
rt_free_timers();
rtapi_data->timer_period = 0;
timer_counts = 0;
max_delay = DEFAULT_MAX_DELAY;
rtapi_data->timer_running = 0;
}
}
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %d exited, name: '%s'\n",
module_id, name);
return 0;
}
int rtapi_snprintf(char *buf, unsigned long int size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = rtapi_vsnprintf(buf, size, fmt, args);
va_end(args);
return i;
}
#define BUFFERLEN 1024
void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) {
char buf[BUFFERLEN];
rtapi_vsnprintf(buf, BUFFERLEN, fmt, ap);
rt_printk(buf);
}
static rtapi_msg_handler_t rtapi_msg_handler = default_rtapi_msg_handler;
rtapi_msg_handler_t rtapi_get_msg_handler(void) {
return rtapi_msg_handler;
}
void rtapi_set_msg_handler(rtapi_msg_handler_t handler) {
if(handler == NULL) rtapi_msg_handler = default_rtapi_msg_handler;
else rtapi_msg_handler = handler;
}
void rtapi_print(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
rtapi_msg_handler(RTAPI_MSG_ALL, fmt, args);
va_end(args);
}
void rtapi_print_msg(msg_level_t level, const char *fmt, ...)
{
va_list args;
if ((level <= msg_level) && (msg_level != RTAPI_MSG_NONE)) {
va_start(args, fmt);
rtapi_msg_handler(level, fmt, args);
va_end(args);
}
}
int rtapi_set_msg_level(int level)
{
if ((level < RTAPI_MSG_NONE) || (level > RTAPI_MSG_ALL)) {
return -EINVAL;
}
msg_level = level;
return 0;
}
int rtapi_get_msg_level(void)
{
return msg_level;
}
long int rtapi_clock_set_period(long int nsecs)
{
RTIME counts, got_counts;
if (nsecs == 0) {
return rtapi_data->timer_period;
}
if (rtapi_data->timer_running) {
return -EINVAL;
}
if ((nsecs < 2000) || (nsecs > 1000000000L)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: ERR: clock_set_period: %ld nsecs, out of range\n",
nsecs);
return -EINVAL;
}
rt_set_periodic_mode();
counts = nano2count((RTIME) nsecs);
if(count2nano(counts) > nsecs) counts--;
got_counts = start_rt_timer(counts);
rtapi_data->timer_period = count2nano(got_counts);
timer_counts = got_counts;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: clock_set_period requested: %ld actual: %ld counts requested: %d actual: %d\n",
nsecs, rtapi_data->timer_period, (int)counts, (int)got_counts);
rtapi_data->timer_running = 1;
max_delay = rtapi_data->timer_period / 4;
return rtapi_data->timer_period;
}
long long int rtapi_get_time(void)
{
return rt_get_cpu_time_ns();
}
long long int rtapi_get_clocks(void)
{
long long int retval;
rdtscll(retval);
return retval;
}
void rtapi_delay(long int nsec)
{
if (nsec > max_delay) {
nsec = max_delay;
}
rt_busy_sleep(nsec);
}
long int rtapi_delay_max(void)
{
return max_delay;
}
int rtapi_prio_highest(void)
{
return 0;
}
int rtapi_prio_lowest(void)
{
return 0xFFF;
}
int rtapi_prio_next_higher(int prio)
{
if (prio <= rtapi_prio_highest()) {
return rtapi_prio_highest();
}
if (prio > rtapi_prio_lowest()) {
return rtapi_prio_lowest();
}
return prio - 1;
}
int rtapi_prio_next_lower(int prio)
{
if (prio >= rtapi_prio_lowest()) {
return rtapi_prio_lowest();
}
if (prio < rtapi_prio_highest()) {
return rtapi_prio_highest();
}
return prio + 1;
}
static void wrapper(long task_id)
{
task_data *task;
task = &task_array[task_id];
(task->taskcode) (task->arg);
task->state = ENDED;
return;
}
#define IP(x) ((x)->ip)
static int rtapi_trap_handler(int vec, int signo, struct pt_regs *regs,
void *task) {
int self = rtapi_task_self();
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: Task %d[%p]: Fault with vec=%d, signo=%d ip=%08lx.\n"
"RTAPI: This fault may not be recoverable without rebooting.\n",
self, task, vec, signo, IP(regs));
rtapi_task_pause(self);
return 0;
}
int rtapi_task_new(void (*taskcode) (void *), void *arg,
int prio, int owner, unsigned long int stacksize, int uses_fp)
{
int n;
long task_id;
int retval;
task_data *task;
rtapi_mutex_get(&(rtapi_data->mutex));
if ((owner < 1) || (owner > RTAPI_MAX_MODULES)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (module_array[owner].state != REALTIME) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
n = 1;
while ((n <= RTAPI_MAX_TASKS) && (task_array[n].state != EMPTY)) {
n++;
}
if (n > RTAPI_MAX_TASKS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EMFILE;
}
task_id = n;
task = &(task_array[n]);
if ((prio < rtapi_prio_highest()) || (prio > rtapi_prio_lowest())) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
ostask_array[task_id] = kmalloc(sizeof(RT_TASK), GFP_USER);
if (ostask_array[task_id] == NULL) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -ENOMEM;
}
task->taskcode = taskcode;
task->arg = arg;
retval = rt_task_init_cpuid(ostask_array[task_id], wrapper, task_id,
stacksize, prio, uses_fp, 0 , rtapi_data->rt_cpu );
if (retval != 0) {
kfree(ostask_array[task_id]);
rtapi_mutex_give(&(rtapi_data->mutex));
if (retval == ENOMEM) {
return -ENOMEM;
}
return -EINVAL;
}
{
int v;
for(v=0; v<RTAI_NR_TRAPS; v++)
rt_set_task_trap_handler(ostask_array[task_id], v, rtapi_trap_handler);
}
task->state = PAUSED;
task->prio = prio;
task->owner = owner;
task->taskcode = taskcode;
rtapi_data->task_count++;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: task %02ld installed by module %02d, priority %d, code: %p\n",
task_id, task->owner, task->prio, taskcode);
rtapi_mutex_give(&(rtapi_data->mutex));
return task_id;
}
int rtapi_task_delete(int task_id)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = task_delete(task_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int task_delete(int task_id)
{
task_data *task;
if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
return -EINVAL;
}
task = &(task_array[task_id]);
if (task->state == EMPTY) {
return -EINVAL;
}
if ((task->state == PERIODIC) || (task->state == FREERUN)) {
rtapi_print_msg(RTAPI_MSG_WARN,
"RTAPI: WARNING: tried to delete task %02d while running\n",
task_id);
rtapi_task_pause(task_id);
}
rt_task_delete(ostask_array[task_id]);
kfree(ostask_array[task_id]);
task->state = EMPTY;
task->prio = 0;
task->owner = 0;
task->taskcode = NULL;
ostask_array[task_id] = NULL;
rtapi_data->task_count--;
if (rtapi_data->task_count == 0) {
if (rtapi_data->timer_running != 0) {
stop_rt_timer();
rt_free_timers();
rtapi_data->timer_period = 0;
max_delay = DEFAULT_MAX_DELAY;
rtapi_data->timer_running = 0;
}
}
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: task %02d deleted\n", task_id);
return 0;
}
int rtapi_task_start(int task_id, unsigned long int period_nsec)
{
int retval;
unsigned long int quo, period_counts;
task_data *task;
if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
return -EINVAL;
}
task = &(task_array[task_id]);
if (task->state != PAUSED) {
return -EINVAL;
}
if ((rtapi_data->timer_running == 0) || (rtapi_data->timer_period == 0)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"RTAPI: could not start task: timer isn't running\n");
return -EINVAL;
}
period_counts = nano2count((RTIME)period_nsec);
quo = (period_counts + timer_counts / 2) / timer_counts;
period_counts = quo * timer_counts;
period_nsec = count2nano(period_counts);
retval = rt_task_make_periodic(ostask_array[task_id],
rt_get_time() + period_counts, period_counts);
if (retval != 0) {
return -EINVAL;
}
task->state = PERIODIC;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: start_task id: %02d\n", task_id);
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: period_nsec: %ld\n", period_nsec);
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: count: %ld\n", period_counts);
return retval;
}
void rtapi_wait(void)
{
int result = rt_task_wait_period();
if(result != 0) {
static int error_printed = 0;
if(error_printed < 10) {
#ifdef RTE_TMROVRN
if(result == RTE_TMROVRN) {
rtapi_print_msg(
error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
"RTAPI: ERROR: Unexpected realtime delay on task %d\n"
"This Message will only display once per session.\n"
"Run the Latency Test and resolve before continuing.\n",
rtapi_task_self());
} else
#endif
#ifdef RTE_UNBLKD
if(result == RTE_UNBLKD) {
rtapi_print_msg(
error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
"RTAPI: ERROR: rt_task_wait_period() returned RTE_UNBLKD (%d).\n", result);
} else
#endif
{
rtapi_print_msg(
error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
"RTAPI: ERROR: rt_task_wait_period() returned %d.\n", result);
}
error_printed++;
if(error_printed == 10)
rtapi_print_msg(
error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
"RTAPI: (further messages will be suppressed)\n");
}
}
}
int rtapi_task_resume(int task_id)
{
int retval;
task_data *task;
if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
return -EINVAL;
}
task = &(task_array[task_id]);
if (task->state != PAUSED) {
return -EINVAL;
}
retval = rt_task_resume(ostask_array[task_id]);
if (retval != 0) {
return -EINVAL;
}
task->state = FREERUN;
return 0;
}
int rtapi_task_pause(int task_id)
{
int retval;
int oldstate;
task_data *task;
if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
return -EINVAL;
}
task = &(task_array[task_id]);
if ((task->state != PERIODIC) && (task->state != FREERUN)) {
return -EINVAL;
}
oldstate = task->state;
task->state = PAUSED;
retval = rt_task_suspend(ostask_array[task_id]);
if (retval != 0) {
task->state = oldstate;
return -EINVAL;
}
return 0;
}
int rtapi_task_self(void)
{
RT_TASK *ptr;
int n;
ptr = rt_whoami();
if (ptr == NULL) {
return -EINVAL;
}
n = 1;
while (n <= RTAPI_MAX_TASKS) {
if (ostask_array[n] == ptr) {
return n;
}
n++;
}
return -EINVAL;
}
int rtapi_shmem_new(int key, int module_id, unsigned long int size)
{
int n;
int shmem_id;
shmem_data *shmem;
if ((key == 0) || (key == RTAPI_KEY)) {
return -EINVAL;
}
rtapi_mutex_get(&(rtapi_data->mutex));
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
if (shmem_array[n].key == key) {
shmem_id = n;
shmem = &(shmem_array[n]);
if (shmem->size < size) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (shmem->rtusers == 0) {
shmem_addr_array[shmem_id] = rtai_kmalloc(key, shmem->size);
if (shmem_addr_array[shmem_id] == NULL) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -ENOMEM;
}
}
if (test_bit(module_id, shmem->bitmap)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
set_bit(module_id, shmem->bitmap);
shmem->rtusers++;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: shmem %02d opened by module %02d\n",
shmem_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return shmem_id;
}
}
n = 1;
while ((n <= RTAPI_MAX_SHMEMS) && (shmem_array[n].key != 0)) {
n++;
}
if (n > RTAPI_MAX_SHMEMS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EMFILE;
}
shmem_id = n;
shmem = &(shmem_array[n]);
shmem_addr_array[shmem_id] = rtai_kmalloc(key, size);
if (shmem_addr_array[shmem_id] == NULL) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -ENOMEM;
}
set_bit(module_id, shmem->bitmap);
shmem->key = key;
shmem->rtusers = 1;
shmem->ulusers = 0;
shmem->size = size;
rtapi_data->shmem_count++;
*((long int *) (shmem_addr_array[shmem_id])) = 0;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: shmem %02d created by module %02d, key: %d, size: %lu\n",
shmem_id, module_id, key, size);
rtapi_mutex_give(&(rtapi_data->mutex));
return shmem_id;
}
int rtapi_shmem_delete(int shmem_id, int module_id)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = shmem_delete(shmem_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int shmem_delete(int shmem_id, int module_id)
{
shmem_data *shmem;
if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) {
return -EINVAL;
}
shmem = &(shmem_array[shmem_id]);
if (shmem->key == 0) {
return -EINVAL;
}
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
return -EINVAL;
}
if (test_bit(module_id, shmem->bitmap) == 0) {
return -EINVAL;
}
clear_bit(module_id, shmem->bitmap);
shmem->rtusers--;
if (shmem->rtusers > 0) {
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: shmem %02d closed by module %02d\n", shmem_id, module_id);
return 0;
}
rtai_kfree(shmem->key);
shmem_addr_array[shmem_id] = NULL;
shmem->rtusers = 0;
if (shmem->ulusers > 0) {
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: shmem %02d unmapped by module %02d\n", shmem_id,
module_id);
return 0;
}
shmem->key = 0;
shmem->size = 0;
rtapi_data->shmem_count--;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: shmem %02d freed by module %02d\n",
shmem_id, module_id);
return 0;
}
int rtapi_shmem_getptr(int shmem_id, void **ptr)
{
if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) {
return -EINVAL;
}
if (shmem_addr_array[shmem_id] == NULL) {
return -EINVAL;
}
*ptr = shmem_addr_array[shmem_id];
return 0;
}
int rtapi_sem_new(int key, int module_id)
{
int n;
int sem_id;
sem_data *sem;
if (key == 0) {
return -EINVAL;
}
rtapi_mutex_get(&(rtapi_data->mutex));
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
if ((sem_array[n].users > 0) && (sem_array[n].key == key)) {
sem_id = n;
sem = &(sem_array[n]);
if (test_bit(module_id, sem->bitmap)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
set_bit(module_id, sem->bitmap);
sem->users++;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: sem %02d opened by module %02d\n", sem_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return sem_id;
}
}
n = 1;
while ((n <= RTAPI_MAX_SEMS) && (sem_array[n].users != 0)) {
n++;
}
if (n > RTAPI_MAX_SEMS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EMFILE;
}
sem_id = n;
sem = &(sem_array[n]);
rt_sem_init(&(ossem_array[sem_id]), 0);
set_bit(module_id, sem->bitmap);
sem->users = 1;
sem->key = key;
rtapi_data->sem_count++;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: sem %02d created by module %02d, key: %d\n",
sem_id, module_id, key);
rtapi_mutex_give(&(rtapi_data->mutex));
return sem_id;
}
int rtapi_sem_delete(int sem_id, int module_id)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = sem_delete(sem_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int sem_delete(int sem_id, int module_id)
{
sem_data *sem;
if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
return -EINVAL;
}
sem = &(sem_array[sem_id]);
if (sem->users == 0) {
return -EINVAL;
}
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
return -EINVAL;
}
if (test_bit(module_id, sem->bitmap) == 0) {
return -EINVAL;
}
clear_bit(module_id, sem->bitmap);
sem->users--;
if (sem->users > 0) {
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: sem %02d closed by module %02d\n", sem_id, module_id);
return 0;
}
rt_sem_delete(&(ossem_array[sem_id]));
sem->users = 0;
sem->key = 0;
rtapi_data->sem_count--;
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: sem %02d deleted by module %02d\n",
sem_id, module_id);
return 0;
}
int rtapi_sem_give(int sem_id)
{
sem_data *sem;
if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
return -EINVAL;
}
sem = &(sem_array[sem_id]);
if (sem->users == 0) {
return -EINVAL;
}
rt_sem_signal(&(ossem_array[sem_id]));
return 0;
}
int rtapi_sem_take(int sem_id)
{
sem_data *sem;
if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
return -EINVAL;
}
sem = &(sem_array[sem_id]);
if (sem->users == 0) {
return -EINVAL;
}
rt_sem_wait(&(ossem_array[sem_id]));
return 0;
}
int rtapi_sem_try(int sem_id)
{
sem_data *sem;
if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
return -EINVAL;
}
sem = &(sem_array[sem_id]);
if (sem->users == 0) {
return -EINVAL;
}
if (rt_sem_wait_if(&(ossem_array[sem_id])) <= 0) {
return -EBUSY;
}
return 0;
}
int rtapi_fifo_new(int key, int module_id, unsigned long int size, char mode)
{
int n, retval;
int fifo_id;
fifo_data *fifo;
if (key == 0) {
return -EINVAL;
}
if ((mode != 'R') && (mode != 'W')) {
return -EINVAL;
}
rtapi_mutex_get(&(rtapi_data->mutex));
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
if ((fifo_array[n].state != UNUSED) && (fifo_array[n].key == key)) {
fifo_id = n;
fifo = &(fifo_array[n]);
if (mode == 'R') {
if (fifo->state & HAS_READER) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EBUSY;
}
fifo->state |= HAS_READER;
fifo->reader = module_id;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d opened for read by module %02d\n",
fifo_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return fifo_id;
} else {
if (fifo->state & HAS_WRITER) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EBUSY;
}
fifo->state |= HAS_WRITER;
fifo->writer = module_id;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d opened for write by module %02d\n",
fifo_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return fifo_id;
}
}
}
n = 1;
while ((n <= RTAPI_MAX_FIFOS) && (fifo_array[n].state != UNUSED)) {
n++;
}
if (n > RTAPI_MAX_FIFOS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EMFILE;
}
fifo_id = n;
fifo = &(fifo_array[n]);
retval = rtf_create(fifo_id, size);
if (retval != 0) {
rtapi_mutex_give(&(rtapi_data->mutex));
if (retval == ENOMEM) {
return -ENOMEM;
}
return -EINVAL;
}
if (mode == 'R') {
fifo->state = HAS_READER;
fifo->reader = module_id;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d created for read by module %02d, key: %d, size: %ld\n",
fifo_id, module_id, key, size);
} else {
fifo->state = HAS_WRITER;
fifo->writer = module_id;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d created for write by module %02d, key: %d, size: %ld\n",
fifo_id, module_id, key, size);
}
fifo->key = key;
fifo->size = size;
rtapi_data->fifo_count++;
rtapi_mutex_give(&(rtapi_data->mutex));
return fifo_id;
}
int rtapi_fifo_delete(int fifo_id, int module_id)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = fifo_delete(fifo_id, module_id);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int fifo_delete(int fifo_id, int module_id)
{
fifo_data *fifo;
if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
return -EINVAL;
}
fifo = &(fifo_array[fifo_id]);
if (fifo->state == UNUSED) {
return -EINVAL;
}
if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
return -EINVAL;
}
if (module_array[module_id].state != REALTIME) {
return -EINVAL;
}
if ((fifo->reader != module_id) && (fifo->writer != module_id)) {
return -EINVAL;
}
if (fifo->reader == module_id) {
fifo->state &= ~HAS_READER;
fifo->reader = 0;
}
if (fifo->writer == module_id) {
fifo->state &= ~HAS_WRITER;
fifo->writer = 0;
}
if (fifo->state != UNUSED) {
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d closed by module %02d\n", fifo_id, module_id);
return 0;
}
while (rtf_destroy(fifo_id) > 0);
fifo->state = UNUSED;
fifo->key = 0;
fifo->size = 0;
rtapi_data->fifo_count--;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: fifo %02d deleted by module %02d\n", fifo_id, module_id);
return 0;
}
int rtapi_fifo_read(int fifo_id, char *buf, unsigned long int size)
{
int retval;
fifo_data *fifo;
if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
return -EINVAL;
}
fifo = &(fifo_array[fifo_id]);
if ((fifo->state & HAS_READER) == 0) {
return -EINVAL;
}
retval = rtf_get(fifo_id, &buf, size);
if (retval < 0) {
return -EINVAL;
}
return retval;
}
int rtapi_fifo_write(int fifo_id, char *buf, unsigned long int size)
{
int retval;
fifo_data *fifo;
if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
return -EINVAL;
}
fifo = &(fifo_array[fifo_id]);
if ((fifo->state & HAS_WRITER) == 0) {
return -EINVAL;
}
retval = rtf_put(fifo_id, buf, size);
if (retval < 0) {
return -EINVAL;
}
return retval;
}
int rtapi_irq_new(unsigned int irq_num, int owner, void (*handler) (void))
{
int n, retval;
int irq_id;
irq_data *irq;
if ((irq_num < 1) || (irq_num > 255)) {
return -EINVAL;
}
if (handler == NULL) {
return -EINVAL;
}
rtapi_mutex_get(&(rtapi_data->mutex));
if ((owner < 1) || (owner > RTAPI_MAX_MODULES)) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
if (module_array[owner].state != REALTIME) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
if (irq_array[n].irq_num == irq_num) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EBUSY;
}
}
n = 1;
while ((n <= RTAPI_MAX_IRQS) && (irq_array[n].irq_num != 0)) {
n++;
}
if (n > RTAPI_MAX_IRQS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -EMFILE;
}
irq_id = n;
irq = &(irq_array[n]);
retval = rt_request_global_irq(irq_num, handler);
if (retval != 0) {
rtapi_mutex_give(&(rtapi_data->mutex));
if (retval == EBUSY) {
return -EBUSY;
} else {
return -EINVAL;
}
}
irq->irq_num = irq_num;
irq->owner = owner;
irq->handler = handler;
rtapi_data->irq_count++;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: handler for IRQ %d installed by module %02d\n",
irq_num, owner);
rtapi_mutex_give(&(rtapi_data->mutex));
return 0;
}
int rtapi_irq_delete(unsigned int irq_num)
{
int retval;
rtapi_mutex_get(&(rtapi_data->mutex));
retval = irq_delete(irq_num);
rtapi_mutex_give(&(rtapi_data->mutex));
return retval;
}
static int irq_delete(unsigned int irq_num)
{
int n, retval;
int irq_id;
irq_data *irq;
if ((irq_num < 1) || (irq_num > 255)) {
return -EINVAL;
}
n = 1;
while ((n <= RTAPI_MAX_IRQS) && (irq_array[n].irq_num != irq_num)) {
n++;
}
if (n > RTAPI_MAX_IRQS) {
return -EINVAL;
}
irq_id = n;
irq = &(irq_array[n]);
rt_shutdown_irq(irq_num);
retval = rt_free_global_irq(irq_num);
if (retval != 0) {
return -EINVAL;
}
irq->irq_num = 0;
irq->owner = 0;
irq->handler = NULL;
rtapi_data->irq_count--;
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: handler for IRQ %d deleted\n", irq_num);
return 0;
}
int rtapi_enable_interrupt(unsigned int irq)
{
rt_startup_irq(irq);
return 0;
}
int rtapi_disable_interrupt(unsigned int irq)
{
rt_shutdown_irq(irq);
return 0;
}
void rtapi_outb(unsigned char byte, unsigned int port)
{
outb(byte, port);
}
unsigned char rtapi_inb(unsigned int port)
{
return inb(port);
}
int rtapi_is_realtime() { return 1; }
int rtapi_is_kernelspace() { return 1; }
EXPORT_SYMBOL(rtapi_init);
EXPORT_SYMBOL(rtapi_exit);
EXPORT_SYMBOL(rtapi_snprintf);
EXPORT_SYMBOL(rtapi_vsnprintf);
EXPORT_SYMBOL(rtapi_print);
EXPORT_SYMBOL(rtapi_print_msg);
EXPORT_SYMBOL(rtapi_set_msg_level);
EXPORT_SYMBOL(rtapi_get_msg_level);
EXPORT_SYMBOL(rtapi_set_msg_handler);
EXPORT_SYMBOL(rtapi_get_msg_handler);
EXPORT_SYMBOL(rtapi_clock_set_period);
EXPORT_SYMBOL(rtapi_get_time);
EXPORT_SYMBOL(rtapi_get_clocks);
EXPORT_SYMBOL(rtapi_delay);
EXPORT_SYMBOL(rtapi_delay_max);
EXPORT_SYMBOL(rtapi_prio_highest);
EXPORT_SYMBOL(rtapi_prio_lowest);
EXPORT_SYMBOL(rtapi_prio_next_higher);
EXPORT_SYMBOL(rtapi_prio_next_lower);
EXPORT_SYMBOL(rtapi_task_new);
EXPORT_SYMBOL(rtapi_task_delete);
EXPORT_SYMBOL(rtapi_task_start);
EXPORT_SYMBOL(rtapi_wait);
EXPORT_SYMBOL(rtapi_task_resume);
EXPORT_SYMBOL(rtapi_task_pause);
EXPORT_SYMBOL(rtapi_task_self);
EXPORT_SYMBOL(rtapi_shmem_new);
EXPORT_SYMBOL(rtapi_shmem_delete);
EXPORT_SYMBOL(rtapi_shmem_getptr);
EXPORT_SYMBOL(rtapi_sem_new);
EXPORT_SYMBOL(rtapi_sem_delete);
EXPORT_SYMBOL(rtapi_sem_give);
EXPORT_SYMBOL(rtapi_sem_take);
EXPORT_SYMBOL(rtapi_sem_try);
EXPORT_SYMBOL(rtapi_fifo_new);
EXPORT_SYMBOL(rtapi_fifo_delete);
EXPORT_SYMBOL(rtapi_fifo_read);
EXPORT_SYMBOL(rtapi_fifo_write);
EXPORT_SYMBOL(rtapi_irq_new);
EXPORT_SYMBOL(rtapi_irq_delete);
EXPORT_SYMBOL(rtapi_enable_interrupt);
EXPORT_SYMBOL(rtapi_disable_interrupt);
EXPORT_SYMBOL(rtapi_outb);
EXPORT_SYMBOL(rtapi_inb);
EXPORT_SYMBOL(rtapi_is_realtime);
EXPORT_SYMBOL(rtapi_is_kernelspace);