/ src / rtapi / rtai_rtapi.c
rtai_rtapi.c
   1  /** RTAPI is a library providing a uniform API for several real time
   2      operating systems.  As of ver 2.0, RTLinux and RTAI are supported.
   3  */
   4  /********************************************************************
   5  * Description:  rtai_rtapi.c
   6  *               Realtime RTAPI implementation for the RTAI platform.
   7  *
   8  * Author: John Kasunich, Paul Corner
   9  * License: GPL Version 2
  10  *    
  11  * Copyright (c) 2004 All rights reserved.
  12  *
  13  * Last change: 
  14  ********************************************************************/
  15  
  16  /** This file, 'rtai_rtapi.c', implements the realtime portion of the
  17      API for the RTAI platform.  The API is defined in rtapi.h, which
  18      includes documentation for all of the API functions.  The non-
  19      real-time portion of the API is implemented in rtai_ulapi.c (for
  20      the RTAI platform).  This implementation attempts to prevent
  21      kernel panics, 'oops'es, and other nasty stuff that can happen
  22      when writing and testing realtime code.  Wherever possible,
  23      common errors are detected and corrected before they can cause a
  24      crash.  This implementation also includes several /proc filesystem
  25      entries and numerous debugging print statements.
  26  */
  27  
  28  /** Copyright (C) 2003 John Kasunich
  29                         <jmkasunich AT users DOT sourceforge DOT net>
  30      Copyright (C) 2003 Paul Corner
  31                         <paul_c AT users DOT sourceforge DOT net>
  32      This library is based on version 1.0, which was released into
  33      the public domain by its author, Fred Proctor.  Thanks Fred!
  34  */
  35  
  36  /* This library is free software; you can redistribute it and/or
  37     modify it under the terms of version 2 of the GNU General Public
  38     License as published by the Free Software Foundation.
  39     This library is distributed in the hope that it will be useful, but
  40     WITHOUT ANY WARRANTY; without even the implied warranty of
  41     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  42     General Public License for more details.
  43  
  44     You should have received a copy of the GNU General Public License
  45     along with this library; if not, write to the Free Software
  46     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  47  */
  48  
  49  /** THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
  50      ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
  51      TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
  52      harming persons must have provisions for completely removing power
  53      from all motors, etc, before persons enter any danger area.  All
  54      machinery must be designed to comply with local and national safety
  55      codes, and the authors of this software can not, and do not, take
  56      any responsibility for such compliance.
  57  
  58      This code was written as part of the EMC HAL project.  For more
  59      information, go to www.linuxcnc.org.
  60  */
  61  
  62  #include <stdarg.h>		/* va_* */
  63  #include <linux/module.h>
  64  #include <linux/kernel.h>
  65  #include <linux/slab.h>		/* replaces malloc.h in recent kernels */
  66  #include <linux/ctype.h>	/* isdigit */
  67  #include <linux/uaccess.h>	/* copy_from_user() */
  68  #include <asm/msr.h>		/* rdtscll() */
  69  
  70  /* get inb(), outb(), ioperm() */
  71  #include <asm/io.h>
  72  
  73  #include <linux/cpumask.h>	/* NR_CPUS, cpu_online() */
  74  
  75  #include "vsnprintf.h"
  76  
  77  #include <rtai.h>
  78  #include <rtai_sched.h>
  79  #if RTAI > 2
  80  #include <rtai_sem.h>
  81  #endif
  82  #include <rtai_shm.h>
  83  #include <rtai_fifos.h>
  84  
  85  #include "rtapi.h"		/* public RTAPI decls */
  86  #include <rtapi_mutex.h>
  87  #include "rtapi_common.h"	/* shared realtime/nonrealtime stuff */
  88  
  89  #ifndef RTAI_NR_TRAPS
  90  #define RTAI_NR_TRAPS HAL_NR_FAULTS
  91  #endif
  92  
  93  #if RTAI < 5
  94  #define rt_free_timers rt_free_timer
  95  #endif
  96  
  97  /* resource data unique to kernel space */
  98  static RT_TASK *ostask_array[RTAPI_MAX_TASKS + 1];
  99  static void *shmem_addr_array[RTAPI_MAX_SHMEMS + 1];
 100  static SEM ossem_array[RTAPI_MAX_SEMS + 1];
 101  
 102  #define DEFAULT_MAX_DELAY 10000
 103  static long int max_delay = DEFAULT_MAX_DELAY;
 104  
 105  // Actual number of RTAI timer counts of the periodic timer
 106  static unsigned long timer_counts; 
 107  
 108  /* module parameters */
 109  
 110  static int msg_level = RTAPI_MSG_ERR;	/* message printing level */
 111  RTAPI_MP_INT(msg_level, "debug message level (default=1)");
 112  
 113  /* other module information */
 114  MODULE_AUTHOR("John Kasunich, Fred Proctor, & Paul Corner");
 115  MODULE_DESCRIPTION("Portable Real Time API for RTAI");
 116  MODULE_LICENSE("GPL");
 117  
 118  
 119  
 120  #include "rtapi_proc.h"		/* proc filesystem decls & code */
 121  
 122  /* the following are internal functions that do the real work associated
 123     with deleting tasks, etc.  They do not check the mutex that protects
 124     the internal data structures.  When someone calls an rtapi_xxx_delete()
 125     function, the rtapi funct gets the mutex before calling one of these
 126     internal functions.  When internal code that already has the mutex
 127     needs to delete something, it calls these functions directly.
 128  */
 129  static int module_delete(int module_id);
 130  static int task_delete(int task_id);
 131  static int shmem_delete(int shmem_id, int module_id);
 132  static int sem_delete(int sem_id, int module_id);
 133  static int fifo_delete(int fifo_id, int module_id);
 134  static int irq_delete(unsigned int irq_num);
 135  
 136  /***********************************************************************
 137  *                   INIT AND SHUTDOWN FUNCTIONS                        *
 138  ************************************************************************/
 139  
 140  int init_module(void)
 141  {
 142      int n;
 143  
 144      /* say hello */
 145      rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Init\n");
 146      /* get master shared memory block from OS and save its address */
 147      rtapi_data = rtai_kmalloc(RTAPI_KEY, sizeof(rtapi_data_t));
 148      if (rtapi_data == NULL) {
 149  	rtapi_print_msg(RTAPI_MSG_ERR,
 150  	    "RTAPI: ERROR: could not open shared memory\n");
 151  	return -ENOMEM;
 152      }
 153      /* perform a global init if needed */
 154      init_rtapi_data(rtapi_data);
 155      /* check revision code */
 156      if (rtapi_data->rev_code != rev_code) {
 157  	/* mismatch - release master shared memory block */
 158  	rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: version mismatch %d vs %d\n", rtapi_data->rev_code, rev_code);
 159  	rtai_kfree(RTAPI_KEY);
 160  	return -EINVAL;
 161      }
 162      /* set up local pointers to global data */
 163      module_array = rtapi_data->module_array;
 164      task_array = rtapi_data->task_array;
 165      shmem_array = rtapi_data->shmem_array;
 166      sem_array = rtapi_data->sem_array;
 167      fifo_array = rtapi_data->fifo_array;
 168      irq_array = rtapi_data->irq_array;
 169      /* perform local init */
 170      for (n = 0; n <= RTAPI_MAX_TASKS; n++) {
 171  	ostask_array[n] = NULL;
 172      }
 173      for (n = 0; n <= RTAPI_MAX_SHMEMS; n++) {
 174  	shmem_addr_array[n] = NULL;
 175      }
 176      rtapi_data->timer_running = 0;
 177      rtapi_data->timer_period = 0;
 178      max_delay = DEFAULT_MAX_DELAY;
 179      rt_linux_use_fpu(1);
 180      /* on SMP machines, we want to put RT code on the last CPU */
 181      n = NR_CPUS-1;
 182      while ( ! cpu_online(n) ) {
 183  	n--;
 184      }
 185      rtapi_data->rt_cpu = n;
 186  
 187  
 188  #ifdef RTAPI_USE_PROCFS
 189      /* set up /proc/rtapi */
 190      if (proc_init() != 0) {
 191  	rtapi_print_msg(RTAPI_MSG_WARN,
 192  	    "RTAPI: WARNING: Could not activate /proc entries\n");
 193  	proc_clean();
 194      }
 195  #endif
 196      /* done */
 197      rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Init complete\n");
 198      return 0;
 199  }
 200  
 201  /* This cleanup code attempts to fix any messes left by modules
 202  that fail to load properly, or fail to clean up after themselves */
 203  
 204  void cleanup_module(void)
 205  {
 206      int n;
 207  
 208      if (rtapi_data == NULL) {
 209  	/* never got inited, nothing to do */
 210  	return;
 211      }
 212      /* grab the mutex */
 213      rtapi_mutex_get(&(rtapi_data->mutex));
 214      rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exiting\n");
 215  
 216      /* clean up leftover modules (start at 1, we don't use ID 0 */
 217      for (n = 1; n <= RTAPI_MAX_MODULES; n++) {
 218  	if (module_array[n].state == REALTIME) {
 219  	    rtapi_print_msg(RTAPI_MSG_WARN,
 220  		"RTAPI: WARNING: module '%s' (ID: %02d) did not call rtapi_exit()\n",
 221  		module_array[n].name, n);
 222  	    module_delete(n);
 223  	}
 224      }
 225      /* cleaning up modules should clean up everything, if not there has
 226         probably been an unrecoverable internal error.... */
 227      for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
 228  	if (irq_array[n].irq_num != 0) {
 229  	    rtapi_print_msg(RTAPI_MSG_ERR,
 230  		"RTAPI: ERROR: interrupt handler %02d not deleted (IRQ %d)\n",
 231  		n, irq_array[n].irq_num);
 232  	    /* probably un-recoverable, but try anyway */
 233  	    irq_delete(irq_array[n].irq_num);
 234  	}
 235      }
 236      for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
 237  	if (fifo_array[n].state != UNUSED) {
 238  	    rtapi_print_msg(RTAPI_MSG_ERR,
 239  		"RTAPI: ERROR: FIFO %02d not deleted\n", n);
 240  	}
 241      }
 242      for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
 243  	while (sem_array[n].users > 0) {
 244  	    rtapi_print_msg(RTAPI_MSG_ERR,
 245  		"RTAPI: ERROR: semaphore %02d not deleted\n", n);
 246  	}
 247      }
 248      for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
 249  	if (shmem_array[n].rtusers > 0) {
 250  	    rtapi_print_msg(RTAPI_MSG_ERR,
 251  		"RTAPI: ERROR: shared memory block %02d not deleted\n", n);
 252  	}
 253      }
 254      for (n = 1; n <= RTAPI_MAX_TASKS; n++) {
 255  	if (task_array[n].state != EMPTY) {
 256  	    rtapi_print_msg(RTAPI_MSG_ERR,
 257  		"RTAPI: ERROR: task %02d not deleted\n", n);
 258  	    /* probably un-recoverable, but try anyway */
 259  	    rtapi_task_pause(n);
 260  	    task_delete(n);
 261  	}
 262      }
 263      if (rtapi_data->timer_running != 0) {
 264  	stop_rt_timer();
 265  	rt_free_timers();
 266  	rtapi_data->timer_period = 0;
 267  	timer_counts = 0;
 268  	rtapi_data->timer_running = 0;
 269  	max_delay = DEFAULT_MAX_DELAY;
 270      }
 271      rtapi_mutex_give(&(rtapi_data->mutex));
 272  #ifdef RTAPI_USE_PROCFS
 273      proc_clean();
 274  #endif
 275      /* release master shared memory block */
 276      rtai_kfree(RTAPI_KEY);
 277      rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exit complete\n");
 278      return;
 279  }
 280  
 281  /***********************************************************************
 282  *                   GENERAL PURPOSE FUNCTIONS                          *
 283  ************************************************************************/
 284  
 285  /* all RTAPI init is done when the rtapi kernel module
 286  is insmoded.  The rtapi_init() and rtapi_exit() functions
 287  simply register that another module is using the RTAPI.
 288  For other RTOSes, things might be different, especially
 289  if the RTOS does not use modules. */
 290  
 291  int rtapi_init(const char *modname)
 292  {
 293      int n, module_id;
 294      module_data *module;
 295  
 296      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: initing module %s\n", modname);
 297      /* get the mutex */
 298      rtapi_mutex_get(&(rtapi_data->mutex));
 299      /* find empty spot in module array */
 300      n = 1;
 301      while ((n <= RTAPI_MAX_MODULES) && (module_array[n].state != NO_MODULE)) {
 302  	n++;
 303      }
 304      if (n > RTAPI_MAX_MODULES) {
 305  	/* no room */
 306  	rtapi_mutex_give(&(rtapi_data->mutex));
 307  	rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: reached module limit %d\n",
 308  	    n);
 309  	return -EMFILE;
 310      }
 311      /* we have space for the module */
 312      module_id = n;
 313      module = &(module_array[n]);
 314      /* update module data */
 315      module->state = REALTIME;
 316      if (modname != NULL) {
 317  	/* use name supplied by caller, truncating if needed */
 318  	rtapi_snprintf(module->name, RTAPI_NAME_LEN, "%s", modname);
 319      } else {
 320  	/* make up a name */
 321  	rtapi_snprintf(module->name, RTAPI_NAME_LEN, "RTMOD%03d", module_id);
 322      }
 323      rtapi_data->rt_module_count++;
 324      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module '%s' loaded, ID: %d\n",
 325  	module->name, module_id);
 326      rtapi_mutex_give(&(rtapi_data->mutex));
 327      return module_id;
 328  }
 329  
 330  int rtapi_exit(int module_id)
 331  {
 332      int retval;
 333  
 334      rtapi_mutex_get(&(rtapi_data->mutex));
 335      retval = module_delete(module_id);
 336      rtapi_mutex_give(&(rtapi_data->mutex));
 337      return retval;
 338  }
 339  
 340  static int module_delete(int module_id)
 341  {
 342      module_data *module;
 343      char name[RTAPI_NAME_LEN + 1];
 344      int n;
 345  
 346      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %d exiting\n", module_id);
 347      /* validate module ID */
 348      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
 349  	return -EINVAL;
 350      }
 351      /* point to the module's data */
 352      module = &(module_array[module_id]);
 353      /* check module status */
 354      if (module->state != REALTIME) {
 355  	/* not an active realtime module */
 356  	return -EINVAL;
 357      }
 358      /* clean up any mess left behind by the module */
 359      for (n = 1; n <= RTAPI_MAX_TASKS; n++) {
 360  	if ((task_array[n].state != EMPTY)
 361  	    && (task_array[n].owner == module_id)) {
 362  	    rtapi_print_msg(RTAPI_MSG_WARN,
 363  		"RTAPI: WARNING: module '%s' failed to delete task %02d\n",
 364  		module->name, n);
 365  	    task_delete(n);
 366  	}
 367      }
 368      for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
 369  	if (test_bit(module_id, shmem_array[n].bitmap)) {
 370  	    rtapi_print_msg(RTAPI_MSG_WARN,
 371  		"RTAPI: WARNING: module '%s' failed to delete shmem %02d\n",
 372  		module->name, n);
 373  	    shmem_delete(n, module_id);
 374  	}
 375      }
 376      for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
 377  	if (test_bit(module_id, sem_array[n].bitmap)) {
 378  	    rtapi_print_msg(RTAPI_MSG_WARN,
 379  		"RTAPI: WARNING: module '%s' failed to delete sem %02d\n",
 380  		module->name, n);
 381  	    sem_delete(n, module_id);
 382  	}
 383      }
 384      for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
 385  	if ((fifo_array[n].reader == module_id) ||
 386  	    (fifo_array[n].writer == module_id)) {
 387  	    rtapi_print_msg(RTAPI_MSG_WARN,
 388  		"RTAPI: WARNING: module '%s' failed to delete fifo %02d\n",
 389  		module->name, n);
 390  	    fifo_delete(n, module_id);
 391  	}
 392      }
 393      for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
 394  	if (irq_array[n].owner == module_id) {
 395  	    rtapi_print_msg(RTAPI_MSG_WARN,
 396  		"RTAPI: WARNING: module '%s' failed to delete handler for IRQ %d\n",
 397  		module->name, irq_array[n].irq_num);
 398  	    irq_delete(irq_array[n].irq_num);
 399  	}
 400      }
 401      /* use snprintf() to do strncpy(), since we don't have string.h */
 402      rtapi_snprintf(name, RTAPI_NAME_LEN, "%s", module->name);
 403      /* update module data */
 404      module->state = NO_MODULE;
 405      module->name[0] = '\0';
 406      rtapi_data->rt_module_count--;
 407      if (rtapi_data->rt_module_count == 0) {
 408  	if (rtapi_data->timer_running != 0) {
 409  	    stop_rt_timer();
 410  	    rt_free_timers();
 411  	    rtapi_data->timer_period = 0;
 412  	    timer_counts = 0;
 413  	    max_delay = DEFAULT_MAX_DELAY;
 414  	    rtapi_data->timer_running = 0;
 415  	}
 416      }
 417      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %d exited, name: '%s'\n",
 418  	module_id, name);
 419      return 0;
 420  }
 421  
 422  int rtapi_snprintf(char *buf, unsigned long int size, const char *fmt, ...)
 423  {
 424      va_list args;
 425      int i;
 426  
 427      va_start(args, fmt);
 428      i = rtapi_vsnprintf(buf, size, fmt, args);
 429      va_end(args);
 430      return i;
 431  }
 432  
 433  #define BUFFERLEN 1024
 434  
 435  void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) {
 436      char buf[BUFFERLEN];
 437      rtapi_vsnprintf(buf, BUFFERLEN, fmt, ap);
 438      rt_printk(buf);
 439  }
 440  static rtapi_msg_handler_t rtapi_msg_handler = default_rtapi_msg_handler;
 441  
 442  rtapi_msg_handler_t rtapi_get_msg_handler(void) {
 443      return rtapi_msg_handler;
 444  }
 445  
 446  void rtapi_set_msg_handler(rtapi_msg_handler_t handler) {
 447      if(handler == NULL) rtapi_msg_handler = default_rtapi_msg_handler;
 448      else rtapi_msg_handler = handler;
 449  }
 450  
 451  void rtapi_print(const char *fmt, ...)
 452  {
 453      va_list args;
 454  
 455      va_start(args, fmt);
 456      rtapi_msg_handler(RTAPI_MSG_ALL, fmt, args);
 457      va_end(args);
 458  }
 459  
 460  
 461  void rtapi_print_msg(msg_level_t level, const char *fmt, ...)
 462  {
 463      va_list args;
 464  
 465      if ((level <= msg_level) && (msg_level != RTAPI_MSG_NONE)) {
 466  	va_start(args, fmt);
 467  	rtapi_msg_handler(level, fmt, args);
 468  	va_end(args);
 469      }
 470  }
 471  
 472  int rtapi_set_msg_level(int level)
 473  {
 474      if ((level < RTAPI_MSG_NONE) || (level > RTAPI_MSG_ALL)) {
 475  	return -EINVAL;
 476      }
 477      msg_level = level;
 478      return 0;
 479  }
 480  
 481  int rtapi_get_msg_level(void)
 482  {
 483      return msg_level;
 484  }
 485  
 486  /***********************************************************************
 487  *                     CLOCK RELATED FUNCTIONS                          *
 488  ************************************************************************/
 489  
 490  long int rtapi_clock_set_period(long int nsecs)
 491  {
 492      RTIME counts, got_counts;
 493  
 494      if (nsecs == 0) {
 495  	/* it's a query, not a command */
 496  	return rtapi_data->timer_period;
 497      }
 498      if (rtapi_data->timer_running) {
 499  	/* already started, can't restart */
 500  	return -EINVAL;
 501      }
 502      /* limit period to 2 micro-seconds min, 1 second max */
 503      if ((nsecs < 2000) || (nsecs > 1000000000L)) {
 504  	rtapi_print_msg(RTAPI_MSG_ERR,
 505  	    "RTAPI: ERR: clock_set_period: %ld nsecs,  out of range\n",
 506  	    nsecs);
 507  	return -EINVAL;
 508      }
 509      rt_set_periodic_mode();
 510      counts = nano2count((RTIME) nsecs);
 511      if(count2nano(counts) > nsecs) counts--;
 512      got_counts = start_rt_timer(counts);
 513      rtapi_data->timer_period = count2nano(got_counts);
 514      timer_counts = got_counts;
 515  
 516      rtapi_print_msg(RTAPI_MSG_DBG,
 517  	"RTAPI: clock_set_period requested: %ld  actual: %ld  counts requested: %d  actual: %d\n",
 518  	nsecs, rtapi_data->timer_period, (int)counts, (int)got_counts);
 519      rtapi_data->timer_running = 1;
 520      max_delay = rtapi_data->timer_period / 4;
 521      return rtapi_data->timer_period;
 522  }
 523  
 524  long long int rtapi_get_time(void)
 525  {
 526      return rt_get_cpu_time_ns();    
 527  }
 528  
 529  /* This returns a result in clocks instead of nS, and needs to be used
 530     with care around CPUs that change the clock speed to save power and
 531     other disgusting, non-realtime oriented behavior.  But at least it
 532     doesn't take a week every time you call it.
 533  */
 534  
 535  long long int rtapi_get_clocks(void)
 536  {
 537      long long int retval;
 538  
 539      rdtscll(retval);
 540      return retval;    
 541  }
 542  
 543  void rtapi_delay(long int nsec)
 544  {
 545      if (nsec > max_delay) {
 546  	nsec = max_delay;
 547      }
 548      rt_busy_sleep(nsec);
 549  }
 550  
 551  long int rtapi_delay_max(void)
 552  {
 553      return max_delay;
 554  }
 555  
 556  /***********************************************************************
 557  *                     TASK RELATED FUNCTIONS                           *
 558  ************************************************************************/
 559  
 560  /* Priority functions.  RTAI uses 0 as the highest priority, as the
 561  number increases, the actual priority of the task decreases. */
 562  
 563  int rtapi_prio_highest(void)
 564  {
 565      return 0;
 566  }
 567  
 568  int rtapi_prio_lowest(void)
 569  {
 570      /* RTAI has LOTS of different priorities - RT_LOWEST_PRIORITY is
 571         0x3FFFFFFF! I don't want such ugly numbers, and we only need a few
 572         levels, so we use 0xFFF (4095) instead */
 573      return 0xFFF;
 574  }
 575  
 576  int rtapi_prio_next_higher(int prio)
 577  {
 578      /* return a valid priority for out of range arg */
 579      if (prio <= rtapi_prio_highest()) {
 580  	return rtapi_prio_highest();
 581      }
 582      if (prio > rtapi_prio_lowest()) {
 583  	return rtapi_prio_lowest();
 584      }
 585  
 586      /* return next higher priority for in-range arg */
 587      return prio - 1;
 588  }
 589  
 590  int rtapi_prio_next_lower(int prio)
 591  {
 592      /* return a valid priority for out of range arg */
 593      if (prio >= rtapi_prio_lowest()) {
 594  	return rtapi_prio_lowest();
 595      }
 596      if (prio < rtapi_prio_highest()) {
 597  	return rtapi_prio_highest();
 598      }
 599      /* return next lower priority for in-range arg */
 600      return prio + 1;
 601  }
 602  
 603  /* We define taskcode as taking a void pointer and returning void, but
 604     rtai wants it to take an int and return void.
 605     We solve this with a wrapper function that meets rtai's needs.
 606     The wrapper functions also properly deals with tasks that return.
 607     (Most tasks are infinite loops, and don't return.)
 608  */
 609  
 610  static void wrapper(long task_id)
 611  {
 612      task_data *task;
 613  
 614      /* point to the task data */
 615      task = &task_array[task_id];
 616      /* call the task function with the task argument */
 617      (task->taskcode) (task->arg);
 618      /* if the task ever returns, we record that fact */
 619      task->state = ENDED;
 620      /* and return to end the thread */
 621      return;
 622  }
 623  
 624  #define IP(x) ((x)->ip)
 625  
 626  static int rtapi_trap_handler(int vec, int signo, struct pt_regs *regs,
 627          void *task) {
 628      int self = rtapi_task_self();
 629      rtapi_print_msg(RTAPI_MSG_ERR,
 630  	"RTAPI: Task %d[%p]: Fault with vec=%d, signo=%d ip=%08lx.\n"
 631  	"RTAPI: This fault may not be recoverable without rebooting.\n",
 632  	self, task, vec, signo, IP(regs));
 633      rtapi_task_pause(self);
 634      return 0;
 635  }
 636  
 637  int rtapi_task_new(void (*taskcode) (void *), void *arg,
 638      int prio, int owner, unsigned long int stacksize, int uses_fp)
 639  {
 640      int n;
 641      long task_id;
 642      int retval;
 643      task_data *task;
 644  
 645      /* get the mutex */
 646      rtapi_mutex_get(&(rtapi_data->mutex));
 647      /* validate owner */
 648      if ((owner < 1) || (owner > RTAPI_MAX_MODULES)) {
 649  	rtapi_mutex_give(&(rtapi_data->mutex));
 650  	return -EINVAL;
 651      }
 652      if (module_array[owner].state != REALTIME) {
 653  	rtapi_mutex_give(&(rtapi_data->mutex));
 654  	return -EINVAL;
 655      }
 656      /* find empty spot in task array */
 657      n = 1;
 658      while ((n <= RTAPI_MAX_TASKS) && (task_array[n].state != EMPTY)) {
 659  	n++;
 660      }
 661      if (n > RTAPI_MAX_TASKS) {
 662  	/* no room */
 663  	rtapi_mutex_give(&(rtapi_data->mutex));
 664  	return -EMFILE;
 665      }
 666      /* we have space for the task */
 667      task_id = n;
 668      task = &(task_array[n]);
 669      /* check requested priority */
 670      if ((prio < rtapi_prio_highest()) || (prio > rtapi_prio_lowest())) {
 671  	rtapi_mutex_give(&(rtapi_data->mutex));
 672  	return -EINVAL;
 673      }
 674      /* get space for the OS's task data - this is around 900 bytes, */
 675      /* so we don't want to statically allocate it for unused tasks. */
 676      ostask_array[task_id] = kmalloc(sizeof(RT_TASK), GFP_USER);
 677      if (ostask_array[task_id] == NULL) {
 678  	rtapi_mutex_give(&(rtapi_data->mutex));
 679  	return -ENOMEM;
 680      }
 681      task->taskcode = taskcode;
 682      task->arg = arg;
 683      /* call OS to initialize the task - use predetermined CPU */
 684      retval = rt_task_init_cpuid(ostask_array[task_id], wrapper, task_id,
 685  	 stacksize, prio, uses_fp, 0 /* signal */, rtapi_data->rt_cpu );
 686      if (retval != 0) {
 687  	/* couldn't create task, free task data memory */
 688  	kfree(ostask_array[task_id]);
 689  	rtapi_mutex_give(&(rtapi_data->mutex));
 690  	if (retval == ENOMEM) {
 691  	    /* not enough space for stack */
 692  	    return -ENOMEM;
 693  	}
 694  	/* unknown error */
 695  	return -EINVAL;
 696      }
 697  
 698      /* request to handle traps in the new task */
 699      {
 700      int v;
 701      for(v=0; v<RTAI_NR_TRAPS; v++)
 702          rt_set_task_trap_handler(ostask_array[task_id], v, rtapi_trap_handler);
 703      }
 704  
 705      /* the task has been created, update data */
 706      task->state = PAUSED;
 707      task->prio = prio;
 708      task->owner = owner;
 709      task->taskcode = taskcode;
 710      rtapi_data->task_count++;
 711      /* announce the birth of a brand new baby task */
 712      rtapi_print_msg(RTAPI_MSG_DBG,
 713  	"RTAPI: task %02ld installed by module %02d, priority %d, code: %p\n",
 714  	task_id, task->owner, task->prio, taskcode);
 715      /* and return the ID to the proud parent */
 716      rtapi_mutex_give(&(rtapi_data->mutex));
 717      return task_id;
 718  }
 719  
 720  int rtapi_task_delete(int task_id)
 721  {
 722      int retval;
 723  
 724      rtapi_mutex_get(&(rtapi_data->mutex));
 725      retval = task_delete(task_id);
 726      rtapi_mutex_give(&(rtapi_data->mutex));
 727      return retval;
 728  }
 729  
 730  static int task_delete(int task_id)
 731  {
 732      task_data *task;
 733  
 734      /* validate task ID */
 735      if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
 736  	return -EINVAL;
 737      }
 738      /* point to the task's data */
 739      task = &(task_array[task_id]);
 740      /* check task status */
 741      if (task->state == EMPTY) {
 742  	/* nothing to delete */
 743  	return -EINVAL;
 744      }
 745      if ((task->state == PERIODIC) || (task->state == FREERUN)) {
 746  	/* task is running, need to stop it */
 747  	rtapi_print_msg(RTAPI_MSG_WARN,
 748  	    "RTAPI: WARNING: tried to delete task %02d while running\n",
 749  	    task_id);
 750  	rtapi_task_pause(task_id);
 751      }
 752      /* get rid of it */
 753      rt_task_delete(ostask_array[task_id]);
 754      /* free kernel memory */
 755      kfree(ostask_array[task_id]);
 756      /* update data */
 757      task->state = EMPTY;
 758      task->prio = 0;
 759      task->owner = 0;
 760      task->taskcode = NULL;
 761      ostask_array[task_id] = NULL;
 762      rtapi_data->task_count--;
 763      /* if no more tasks, stop the timer */
 764      if (rtapi_data->task_count == 0) {
 765  	if (rtapi_data->timer_running != 0) {
 766  	    stop_rt_timer();
 767  	    rt_free_timers();
 768  	    rtapi_data->timer_period = 0;
 769  	    max_delay = DEFAULT_MAX_DELAY;
 770  	    rtapi_data->timer_running = 0;
 771  	}
 772      }
 773      /* done */
 774      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: task %02d deleted\n", task_id);
 775      return 0;
 776  }
 777  
 778  int rtapi_task_start(int task_id, unsigned long int period_nsec)
 779  {
 780      int retval;
 781      unsigned long int quo, period_counts;
 782      task_data *task;
 783  
 784      /* validate task ID */
 785      if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
 786  	return -EINVAL;
 787      }
 788      /* point to the task's data */
 789      task = &(task_array[task_id]);
 790      /* is task ready to be started? */
 791      if (task->state != PAUSED) {
 792  	return -EINVAL;
 793      }
 794      /* can't start periodic tasks if timer isn't running */
 795      if ((rtapi_data->timer_running == 0) || (rtapi_data->timer_period == 0)) {
 796          rtapi_print_msg(RTAPI_MSG_ERR, 
 797                  "RTAPI: could not start task: timer isn't running\n");
 798  	return -EINVAL;
 799      }
 800  
 801      period_counts = nano2count((RTIME)period_nsec);  
 802      quo = (period_counts + timer_counts / 2) / timer_counts;
 803      period_counts = quo * timer_counts;
 804      period_nsec = count2nano(period_counts);
 805  
 806      /* start the task */
 807      retval = rt_task_make_periodic(ostask_array[task_id],
 808  	rt_get_time() + period_counts, period_counts);
 809      if (retval != 0) {
 810  	return -EINVAL;
 811      }
 812      /* ok, task is started */
 813      task->state = PERIODIC;
 814      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: start_task id: %02d\n", task_id);
 815      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: period_nsec: %ld\n", period_nsec);
 816      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: count: %ld\n", period_counts);
 817      return retval;
 818  }
 819  
 820  void rtapi_wait(void)
 821  {
 822      int result = rt_task_wait_period();
 823      if(result != 0) {
 824  	static int error_printed = 0;
 825  	if(error_printed < 10) {
 826  #ifdef RTE_TMROVRN
 827  	    if(result == RTE_TMROVRN) {
 828  		rtapi_print_msg(
 829  		    error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
 830  		    "RTAPI: ERROR: Unexpected realtime delay on task %d\n" 
 831  		    "This Message will only display once per session.\n"
 832  		    "Run the Latency Test and resolve before continuing.\n", 
 833  		    rtapi_task_self());
 834  	    } else
 835  #endif
 836  #ifdef RTE_UNBLKD
 837  		    if(result == RTE_UNBLKD) {
 838  		rtapi_print_msg(
 839  		    error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
 840  		    "RTAPI: ERROR: rt_task_wait_period() returned RTE_UNBLKD (%d).\n", result);
 841  	    } else
 842  #endif
 843  	    {
 844  		rtapi_print_msg(
 845  		    error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
 846  		    "RTAPI: ERROR: rt_task_wait_period() returned %d.\n", result);
 847  	    }
 848  	    error_printed++;
 849  	    if(error_printed == 10)
 850  	        rtapi_print_msg(
 851  		    error_printed == 0 ? RTAPI_MSG_ERR : RTAPI_MSG_WARN,
 852  		    "RTAPI: (further messages will be suppressed)\n");
 853  	}
 854      }
 855  }
 856  
 857  int rtapi_task_resume(int task_id)
 858  {
 859      int retval;
 860      task_data *task;
 861  
 862      /* validate task ID */
 863      if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
 864  	return -EINVAL;
 865      }
 866      /* point to the task's data */
 867      task = &(task_array[task_id]);
 868      /* is task ready to be started? */
 869      if (task->state != PAUSED) {
 870  	return -EINVAL;
 871      }
 872      /* start the task */
 873      retval = rt_task_resume(ostask_array[task_id]);
 874      if (retval != 0) {
 875  	return -EINVAL;
 876      }
 877      /* update task data */
 878      task->state = FREERUN;
 879      return 0;
 880  }
 881  
 882  int rtapi_task_pause(int task_id)
 883  {
 884      int retval;
 885      int oldstate;
 886      task_data *task;
 887  
 888      /* validate task ID */
 889      if ((task_id < 1) || (task_id > RTAPI_MAX_TASKS)) {
 890  	return -EINVAL;
 891      }
 892      /* point to the task's data */
 893      task = &(task_array[task_id]);
 894      /* is it running? */
 895      if ((task->state != PERIODIC) && (task->state != FREERUN)) {
 896  	return -EINVAL;
 897      }
 898      /* pause the task */
 899      oldstate = task->state;
 900      task->state = PAUSED;
 901      retval = rt_task_suspend(ostask_array[task_id]);
 902      if (retval != 0) {
 903          task->state = oldstate;
 904  	return -EINVAL;
 905      }
 906      /* update task data */
 907      return 0;
 908  }
 909  
 910  int rtapi_task_self(void)
 911  {
 912      RT_TASK *ptr;
 913      int n;
 914  
 915      /* ask OS for pointer to its data for the current task */
 916      ptr = rt_whoami();
 917      if (ptr == NULL) {
 918  	/* called from outside a task? */
 919  	return -EINVAL;
 920      }
 921      /* find matching entry in task array */
 922      n = 1;
 923      while (n <= RTAPI_MAX_TASKS) {
 924  	if (ostask_array[n] == ptr) {
 925  	    /* found a match */
 926  	    return n;
 927  	}
 928  	n++;
 929      }
 930      return -EINVAL;
 931  }
 932  
 933  /***********************************************************************
 934  *                  SHARED MEMORY RELATED FUNCTIONS                     *
 935  ************************************************************************/
 936  
 937  int rtapi_shmem_new(int key, int module_id, unsigned long int size)
 938  {
 939      int n;
 940      int shmem_id;
 941      shmem_data *shmem;
 942  
 943      /* key must be non-zero, and also cannot match the key that RTAPI uses */
 944      if ((key == 0) || (key == RTAPI_KEY)) {
 945  	return -EINVAL;
 946      }
 947      /* get the mutex */
 948      rtapi_mutex_get(&(rtapi_data->mutex));
 949      /* validate module_id */
 950      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
 951  	rtapi_mutex_give(&(rtapi_data->mutex));
 952  	return -EINVAL;
 953      }
 954      if (module_array[module_id].state != REALTIME) {
 955  	rtapi_mutex_give(&(rtapi_data->mutex));
 956  	return -EINVAL;
 957      }
 958      /* check if a block is already open for this key */
 959      for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) {
 960  	if (shmem_array[n].key == key) {
 961  	    /* found a match */
 962  	    shmem_id = n;
 963  	    shmem = &(shmem_array[n]);
 964  	    /* is it big enough? */
 965  	    if (shmem->size < size) {
 966  		rtapi_mutex_give(&(rtapi_data->mutex));
 967  		return -EINVAL;
 968  	    }
 969  	    /* yes, has it been mapped into kernel space? */
 970  	    if (shmem->rtusers == 0) {
 971  		/* no, map it and save the address */
 972  		shmem_addr_array[shmem_id] = rtai_kmalloc(key, shmem->size);
 973  		if (shmem_addr_array[shmem_id] == NULL) {
 974  		    rtapi_mutex_give(&(rtapi_data->mutex));
 975  		    return -ENOMEM;
 976  		}
 977  	    }
 978  	    /* is this module already using it? */
 979  	    if (test_bit(module_id, shmem->bitmap)) {
 980  		rtapi_mutex_give(&(rtapi_data->mutex));
 981  		return -EINVAL;
 982  	    }
 983  	    /* update usage data */
 984  	    set_bit(module_id, shmem->bitmap);
 985  	    shmem->rtusers++;
 986  	    /* announce another user for this shmem */
 987  	    rtapi_print_msg(RTAPI_MSG_DBG,
 988  		"RTAPI: shmem %02d opened by module %02d\n",
 989  		shmem_id, module_id);
 990  	    rtapi_mutex_give(&(rtapi_data->mutex));
 991  	    return shmem_id;
 992  	}
 993      }
 994      /* find empty spot in shmem array */
 995      n = 1;
 996      while ((n <= RTAPI_MAX_SHMEMS) && (shmem_array[n].key != 0)) {
 997  	n++;
 998      }
 999      if (n > RTAPI_MAX_SHMEMS) {
1000  	/* no room */
1001  	rtapi_mutex_give(&(rtapi_data->mutex));
1002  	return -EMFILE;
1003      }
1004      /* we have space for the block data */
1005      shmem_id = n;
1006      shmem = &(shmem_array[n]);
1007      /* get shared memory block from OS and save its address */
1008      shmem_addr_array[shmem_id] = rtai_kmalloc(key, size);
1009      if (shmem_addr_array[shmem_id] == NULL) {
1010  	rtapi_mutex_give(&(rtapi_data->mutex));
1011  	return -ENOMEM;
1012      }
1013      /* the block has been created, update data */
1014      set_bit(module_id, shmem->bitmap);
1015      shmem->key = key;
1016      shmem->rtusers = 1;
1017      shmem->ulusers = 0;
1018      shmem->size = size;
1019      rtapi_data->shmem_count++;
1020      /* zero the first word of the shmem area */
1021      *((long int *) (shmem_addr_array[shmem_id])) = 0;
1022      /* announce the birth of a brand new baby shmem */
1023      rtapi_print_msg(RTAPI_MSG_DBG,
1024  	"RTAPI: shmem %02d created by module %02d, key: %d, size: %lu\n",
1025  	shmem_id, module_id, key, size);
1026      /* and return the ID to the proud parent */
1027      rtapi_mutex_give(&(rtapi_data->mutex));
1028      return shmem_id;
1029  }
1030  
1031  int rtapi_shmem_delete(int shmem_id, int module_id)
1032  {
1033      int retval;
1034  
1035      rtapi_mutex_get(&(rtapi_data->mutex));
1036      retval = shmem_delete(shmem_id, module_id);
1037      rtapi_mutex_give(&(rtapi_data->mutex));
1038      return retval;
1039  }
1040  
1041  static int shmem_delete(int shmem_id, int module_id)
1042  {
1043      shmem_data *shmem;
1044  
1045      /* validate shmem ID */
1046      if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) {
1047  	return -EINVAL;
1048      }
1049      /* point to the shmem's data */
1050      shmem = &(shmem_array[shmem_id]);
1051      /* is the block valid? */
1052      if (shmem->key == 0) {
1053  	return -EINVAL;
1054      }
1055      /* validate module_id */
1056      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
1057  	return -EINVAL;
1058      }
1059      if (module_array[module_id].state != REALTIME) {
1060  	return -EINVAL;
1061      }
1062      /* is this module using the block? */
1063      if (test_bit(module_id, shmem->bitmap) == 0) {
1064  	return -EINVAL;
1065      }
1066      /* OK, we're no longer using it */
1067      clear_bit(module_id, shmem->bitmap);
1068      shmem->rtusers--;
1069      /* is somebody else still using the block? */
1070      if (shmem->rtusers > 0) {
1071  	/* yes, we're done for now */
1072  	rtapi_print_msg(RTAPI_MSG_DBG,
1073  	    "RTAPI: shmem %02d closed by module %02d\n", shmem_id, module_id);
1074  	return 0;
1075      }
1076      /* no other realtime users, free the shared memory from kernel space */
1077      rtai_kfree(shmem->key);
1078      shmem_addr_array[shmem_id] = NULL;
1079      shmem->rtusers = 0;
1080      /* are any user processes using the block? */
1081      if (shmem->ulusers > 0) {
1082  	/* yes, we're done for now */
1083  	rtapi_print_msg(RTAPI_MSG_DBG,
1084  	    "RTAPI: shmem %02d unmapped by module %02d\n", shmem_id,
1085  	    module_id);
1086  	return 0;
1087      }
1088      /* no other users at all, this ID is now free */
1089      /* update the data array and usage count */
1090      shmem->key = 0;
1091      shmem->size = 0;
1092      rtapi_data->shmem_count--;
1093      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: shmem %02d freed by module %02d\n",
1094  	shmem_id, module_id);
1095      return 0;
1096  }
1097  
1098  int rtapi_shmem_getptr(int shmem_id, void **ptr)
1099  {
1100      /* validate shmem ID */
1101      if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) {
1102  	return -EINVAL;
1103      }
1104      /* is the block mapped? */
1105      if (shmem_addr_array[shmem_id] == NULL) {
1106  	return -EINVAL;
1107      }
1108      /* pass memory address back to caller */
1109      *ptr = shmem_addr_array[shmem_id];
1110      return 0;
1111  }
1112  
1113  /***********************************************************************
1114  *                    SEMAPHORE RELATED FUNCTIONS                       *
1115  ************************************************************************/
1116  
1117  int rtapi_sem_new(int key, int module_id)
1118  {
1119      int n;
1120      int sem_id;
1121      sem_data *sem;
1122  
1123      /* key must be non-zero */
1124      if (key == 0) {
1125  	return -EINVAL;
1126      }
1127      /* get the mutex */
1128      rtapi_mutex_get(&(rtapi_data->mutex));
1129      /* validate module_id */
1130      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
1131  	rtapi_mutex_give(&(rtapi_data->mutex));
1132  	return -EINVAL;
1133      }
1134      if (module_array[module_id].state != REALTIME) {
1135  	rtapi_mutex_give(&(rtapi_data->mutex));
1136  	return -EINVAL;
1137      }
1138      /* check if a semaphore already exists for this key */
1139      for (n = 1; n <= RTAPI_MAX_SEMS; n++) {
1140  	if ((sem_array[n].users > 0) && (sem_array[n].key == key)) {
1141  	    /* found a match */
1142  	    sem_id = n;
1143  	    sem = &(sem_array[n]);
1144  	    /* is this module already using it? */
1145  	    if (test_bit(module_id, sem->bitmap)) {
1146  		/* yes, can't open it again */
1147  		rtapi_mutex_give(&(rtapi_data->mutex));
1148  		return -EINVAL;
1149  	    }
1150  	    /* update usage data */
1151  	    set_bit(module_id, sem->bitmap);
1152  	    sem->users++;
1153  	    /* announce another user for this semaphore */
1154  	    rtapi_print_msg(RTAPI_MSG_DBG,
1155  		"RTAPI: sem %02d opened by module %02d\n", sem_id, module_id);
1156  	    rtapi_mutex_give(&(rtapi_data->mutex));
1157  	    return sem_id;
1158  	}
1159      }
1160      /* find empty spot in sem array */
1161      n = 1;
1162      while ((n <= RTAPI_MAX_SEMS) && (sem_array[n].users != 0)) {
1163  	n++;
1164      }
1165      if (n > RTAPI_MAX_SEMS) {
1166  	/* no room */
1167  	rtapi_mutex_give(&(rtapi_data->mutex));
1168  	return -EMFILE;
1169      }
1170      /* we have space for the semaphore */
1171      sem_id = n;
1172      sem = &(sem_array[n]);
1173      /* ask the OS to initialize the semaphore */
1174      rt_sem_init(&(ossem_array[sem_id]), 0);
1175      /* the semaphore has been created, update data */
1176      set_bit(module_id, sem->bitmap);
1177      sem->users = 1;
1178      sem->key = key;
1179      rtapi_data->sem_count++;
1180      /* announce the birth of a brand new baby semaphore */
1181      rtapi_print_msg(RTAPI_MSG_DBG,
1182  	"RTAPI: sem %02d created by module %02d, key: %d\n",
1183  	sem_id, module_id, key);
1184      /* and return the ID to the proud parent */
1185      rtapi_mutex_give(&(rtapi_data->mutex));
1186      return sem_id;
1187  }
1188  
1189  int rtapi_sem_delete(int sem_id, int module_id)
1190  {
1191      int retval;
1192  
1193      rtapi_mutex_get(&(rtapi_data->mutex));
1194      retval = sem_delete(sem_id, module_id);
1195      rtapi_mutex_give(&(rtapi_data->mutex));
1196      return retval;
1197  }
1198  
1199  static int sem_delete(int sem_id, int module_id)
1200  {
1201      sem_data *sem;
1202  
1203      /* validate sem ID */
1204      if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
1205  	return -EINVAL;
1206      }
1207      /* point to the semaphores's data */
1208      sem = &(sem_array[sem_id]);
1209      /* is the semaphore valid? */
1210      if (sem->users == 0) {
1211  	return -EINVAL;
1212      }
1213      /* validate module_id */
1214      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
1215  	return -EINVAL;
1216      }
1217      if (module_array[module_id].state != REALTIME) {
1218  	return -EINVAL;
1219      }
1220      /* is this module using the semaphore? */
1221      if (test_bit(module_id, sem->bitmap) == 0) {
1222  	return -EINVAL;
1223      }
1224      /* OK, we're no longer using it */
1225      clear_bit(module_id, sem->bitmap);
1226      sem->users--;
1227      /* is somebody else still using the semaphore */
1228      if (sem->users > 0) {
1229  	/* yes, we're done for now */
1230  	rtapi_print_msg(RTAPI_MSG_DBG,
1231  	    "RTAPI: sem %02d closed by module %02d\n", sem_id, module_id);
1232  	return 0;
1233      }
1234      /* no other users, ask the OS to shut down the semaphore */
1235      rt_sem_delete(&(ossem_array[sem_id]));
1236      /* update the data array and usage count */
1237      sem->users = 0;
1238      sem->key = 0;
1239      rtapi_data->sem_count--;
1240      rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: sem %02d deleted by module %02d\n",
1241  	sem_id, module_id);
1242      return 0;
1243  }
1244  
1245  int rtapi_sem_give(int sem_id)
1246  {
1247      sem_data *sem;
1248  
1249      /* validate sem ID */
1250      if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
1251  	return -EINVAL;
1252      }
1253      /* point to the semaphores's data */
1254      sem = &(sem_array[sem_id]);
1255      /* is the semaphore valid? */
1256      if (sem->users == 0) {
1257  	return -EINVAL;
1258      }
1259      /* give up the semaphore */
1260      rt_sem_signal(&(ossem_array[sem_id]));
1261      return 0;
1262  }
1263  
1264  int rtapi_sem_take(int sem_id)
1265  {
1266      sem_data *sem;
1267  
1268      /* validate sem ID */
1269      if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
1270  	return -EINVAL;
1271      }
1272      /* point to the semaphores's data */
1273      sem = &(sem_array[sem_id]);
1274      /* is the semaphore valid? */
1275      if (sem->users == 0) {
1276  	return -EINVAL;
1277      }
1278      /* get the semaphore */
1279      rt_sem_wait(&(ossem_array[sem_id]));
1280      return 0;
1281  }
1282  
1283  int rtapi_sem_try(int sem_id)
1284  {
1285      sem_data *sem;
1286  
1287      /* validate sem ID */
1288      if ((sem_id < 1) || (sem_id > RTAPI_MAX_SEMS)) {
1289  	return -EINVAL;
1290      }
1291      /* point to the semaphores's data */
1292      sem = &(sem_array[sem_id]);
1293      /* is the semaphore valid? */
1294      if (sem->users == 0) {
1295  	return -EINVAL;
1296      }
1297      /* try the semaphore */
1298      if (rt_sem_wait_if(&(ossem_array[sem_id])) <= 0) {
1299  	return -EBUSY;
1300      }
1301      return 0;
1302  }
1303  
1304  /***********************************************************************
1305  *                        FIFO RELATED FUNCTIONS                        *
1306  ************************************************************************/
1307  
1308  int rtapi_fifo_new(int key, int module_id, unsigned long int size, char mode)
1309  {
1310      int n, retval;
1311      int fifo_id;
1312      fifo_data *fifo;
1313  
1314      /* key must be non-zero */
1315      if (key == 0) {
1316  	return -EINVAL;
1317      }
1318      /* mode must be "R" or "W" */
1319      if ((mode != 'R') && (mode != 'W')) {
1320  	return -EINVAL;
1321      }
1322      /* get the mutex */
1323      rtapi_mutex_get(&(rtapi_data->mutex));
1324      /* validate module_id */
1325      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
1326  	rtapi_mutex_give(&(rtapi_data->mutex));
1327  	return -EINVAL;
1328      }
1329      if (module_array[module_id].state != REALTIME) {
1330  	rtapi_mutex_give(&(rtapi_data->mutex));
1331  	return -EINVAL;
1332      }
1333      /* check if a fifo already exists for this key */
1334      for (n = 1; n <= RTAPI_MAX_FIFOS; n++) {
1335  	if ((fifo_array[n].state != UNUSED) && (fifo_array[n].key == key)) {
1336  	    /* found a match */
1337  	    fifo_id = n;
1338  	    fifo = &(fifo_array[n]);
1339  	    /* is the desired mode available */
1340  	    if (mode == 'R') {
1341  		if (fifo->state & HAS_READER) {
1342  		    rtapi_mutex_give(&(rtapi_data->mutex));
1343  		    return -EBUSY;
1344  		}
1345  		/* available, update status */
1346  		fifo->state |= HAS_READER;
1347  		fifo->reader = module_id;
1348  		/* announce */
1349  		rtapi_print_msg(RTAPI_MSG_DBG,
1350  		    "RTAPI: fifo %02d opened for read by module %02d\n",
1351  		    fifo_id, module_id);
1352  		rtapi_mutex_give(&(rtapi_data->mutex));
1353  		return fifo_id;
1354  	    } else {		/* mode == 'W' */
1355  
1356  		if (fifo->state & HAS_WRITER) {
1357  		    rtapi_mutex_give(&(rtapi_data->mutex));
1358  		    return -EBUSY;
1359  		}
1360  		/* available, update status */
1361  		fifo->state |= HAS_WRITER;
1362  		fifo->writer = module_id;
1363  		/* announce */
1364  		rtapi_print_msg(RTAPI_MSG_DBG,
1365  		    "RTAPI: fifo %02d opened for write by module %02d\n",
1366  		    fifo_id, module_id);
1367  		rtapi_mutex_give(&(rtapi_data->mutex));
1368  		return fifo_id;
1369  	    }
1370  	}
1371      }
1372      /* find empty spot in fifo array */
1373      n = 1;
1374      while ((n <= RTAPI_MAX_FIFOS) && (fifo_array[n].state != UNUSED)) {
1375  	n++;
1376      }
1377      if (n > RTAPI_MAX_FIFOS) {
1378  	/* no room */
1379  	rtapi_mutex_give(&(rtapi_data->mutex));
1380  	return -EMFILE;
1381      }
1382      /* we have a free ID for the fifo */
1383      fifo_id = n;
1384      fifo = &(fifo_array[n]);
1385      /* create the fifo */
1386      retval = rtf_create(fifo_id, size);
1387      /* rtf_create() returns 0 on success */
1388      if (retval != 0) {
1389  	/* create failed */
1390  	rtapi_mutex_give(&(rtapi_data->mutex));
1391  	if (retval == ENOMEM) {
1392  	    /* couldn't allocate memory */
1393  	    return -ENOMEM;
1394  	}
1395  	/* some other failure */
1396  	return -EINVAL;
1397      }
1398      /* the fifo has been created, update data */
1399      if (mode == 'R') {
1400  	fifo->state = HAS_READER;
1401  	fifo->reader = module_id;
1402  	rtapi_print_msg(RTAPI_MSG_DBG,
1403  	    "RTAPI: fifo %02d created for read by module %02d, key: %d, size: %ld\n",
1404  	    fifo_id, module_id, key, size);
1405      } else {			/* mode == 'W' */
1406  
1407  	fifo->state = HAS_WRITER;
1408  	fifo->writer = module_id;
1409  	rtapi_print_msg(RTAPI_MSG_DBG,
1410  	    "RTAPI: fifo %02d created for write by module %02d, key: %d, size: %ld\n",
1411  	    fifo_id, module_id, key, size);
1412      }
1413      fifo->key = key;
1414      fifo->size = size;
1415      rtapi_data->fifo_count++;
1416      /* and return the ID */
1417      rtapi_mutex_give(&(rtapi_data->mutex));
1418      return fifo_id;
1419  }
1420  
1421  int rtapi_fifo_delete(int fifo_id, int module_id)
1422  {
1423      int retval;
1424  
1425      rtapi_mutex_get(&(rtapi_data->mutex));
1426      retval = fifo_delete(fifo_id, module_id);
1427      rtapi_mutex_give(&(rtapi_data->mutex));
1428      return retval;
1429  }
1430  
1431  static int fifo_delete(int fifo_id, int module_id)
1432  {
1433      fifo_data *fifo;
1434  
1435      /* validate fifo ID */
1436      if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
1437  	return -EINVAL;
1438      }
1439      /* point to the fifo's data */
1440      fifo = &(fifo_array[fifo_id]);
1441      /* is the fifo valid? */
1442      if (fifo->state == UNUSED) {
1443  	return -EINVAL;
1444      }
1445      /* validate module_id */
1446      if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) {
1447  	return -EINVAL;
1448      }
1449      if (module_array[module_id].state != REALTIME) {
1450  	return -EINVAL;
1451      }
1452      /* is this module using the fifo? */
1453      if ((fifo->reader != module_id) && (fifo->writer != module_id)) {
1454  	return -EINVAL;
1455      }
1456      /* update fifo state */
1457      if (fifo->reader == module_id) {
1458  	fifo->state &= ~HAS_READER;
1459  	fifo->reader = 0;
1460      }
1461      if (fifo->writer == module_id) {
1462  	fifo->state &= ~HAS_WRITER;
1463  	fifo->writer = 0;
1464      }
1465      /* is somebody else still using the fifo */
1466      if (fifo->state != UNUSED) {
1467  	/* yes, done for now */
1468  	rtapi_print_msg(RTAPI_MSG_DBG,
1469  	    "RTAPI: fifo %02d closed by module %02d\n", fifo_id, module_id);
1470  	return 0;
1471      }
1472      /* no other users, call the OS to destroy the fifo */
1473      /* OS returns open count, loop until truly destroyed */
1474      while (rtf_destroy(fifo_id) > 0);
1475      /* update the data array and usage count */
1476      fifo->state = UNUSED;
1477      fifo->key = 0;
1478      fifo->size = 0;
1479      rtapi_data->fifo_count--;
1480      rtapi_print_msg(RTAPI_MSG_DBG,
1481  	"RTAPI: fifo %02d deleted by module %02d\n", fifo_id, module_id);
1482      return 0;
1483  }
1484  
1485  int rtapi_fifo_read(int fifo_id, char *buf, unsigned long int size)
1486  {
1487      int retval;
1488      fifo_data *fifo;
1489  
1490      /* validate fifo ID */
1491      if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
1492  	return -EINVAL;
1493      }
1494      /* point to the fifo's data */
1495      fifo = &(fifo_array[fifo_id]);
1496      /* is the fifo valid? */
1497      if ((fifo->state & HAS_READER) == 0) {
1498  	return -EINVAL;
1499      }
1500      /* get whatever data is available */
1501      retval = rtf_get(fifo_id, &buf, size);
1502      if (retval < 0) {
1503  	return -EINVAL;
1504      }
1505      return retval;
1506  }
1507  
1508  int rtapi_fifo_write(int fifo_id, char *buf, unsigned long int size)
1509  {
1510      int retval;
1511      fifo_data *fifo;
1512  
1513      /* validate fifo ID */
1514      if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) {
1515  	return -EINVAL;
1516      }
1517      /* point to the fifo's data */
1518      fifo = &(fifo_array[fifo_id]);
1519      /* is the fifo valid? */
1520      if ((fifo->state & HAS_WRITER) == 0) {
1521  	return -EINVAL;
1522      }
1523      /* put as much data as possible */
1524      retval = rtf_put(fifo_id, buf, size);
1525      if (retval < 0) {
1526  	return -EINVAL;
1527      }
1528      return retval;
1529  }
1530  
1531  /***********************************************************************
1532  *                    INTERRUPT RELATED FUNCTIONS                       *
1533  ************************************************************************/
1534  
1535  int rtapi_irq_new(unsigned int irq_num, int owner, void (*handler) (void))
1536  {
1537      int n, retval;
1538      int irq_id;
1539      irq_data *irq;
1540  
1541      /* validate irq */
1542      if ((irq_num < 1) || (irq_num > 255)) {
1543  	return -EINVAL;
1544      }
1545      /* validate handler */
1546      if (handler == NULL) {
1547  	return -EINVAL;
1548      }
1549      /* get the mutex */
1550      rtapi_mutex_get(&(rtapi_data->mutex));
1551      /* validate owner */
1552      if ((owner < 1) || (owner > RTAPI_MAX_MODULES)) {
1553  	rtapi_mutex_give(&(rtapi_data->mutex));
1554  	return -EINVAL;
1555      }
1556      if (module_array[owner].state != REALTIME) {
1557  	rtapi_mutex_give(&(rtapi_data->mutex));
1558  	return -EINVAL;
1559      }
1560      /* check if a handler already exists for this irq */
1561      for (n = 1; n <= RTAPI_MAX_IRQS; n++) {
1562  	if (irq_array[n].irq_num == irq_num) {
1563  	    /* found a match */
1564  	    rtapi_mutex_give(&(rtapi_data->mutex));
1565  	    return -EBUSY;
1566  	}
1567      }
1568      /* find empty spot in irq array */
1569      n = 1;
1570      while ((n <= RTAPI_MAX_IRQS) && (irq_array[n].irq_num != 0)) {
1571  	n++;
1572      }
1573      if (n > RTAPI_MAX_IRQS) {
1574  	/* no room */
1575  	rtapi_mutex_give(&(rtapi_data->mutex));
1576  	return -EMFILE;
1577      }
1578      /* we have space for the irq */
1579      irq_id = n;
1580      irq = &(irq_array[n]);
1581      /* install the handler */
1582      retval = rt_request_global_irq(irq_num, handler);
1583      if (retval != 0) {
1584  	rtapi_mutex_give(&(rtapi_data->mutex));
1585  	if (retval == EBUSY) {
1586  	    return -EBUSY;
1587  	} else {
1588  	    return -EINVAL;
1589  	}
1590      }
1591      /* update data */
1592      irq->irq_num = irq_num;
1593      irq->owner = owner;
1594      irq->handler = handler;
1595      rtapi_data->irq_count++;
1596      /* announce the new interrupt handler */
1597      rtapi_print_msg(RTAPI_MSG_DBG,
1598  	"RTAPI: handler for IRQ %d installed by module %02d\n",
1599  	irq_num, owner);
1600      /* and return success */
1601      rtapi_mutex_give(&(rtapi_data->mutex));
1602      return 0;
1603  }
1604  
1605  int rtapi_irq_delete(unsigned int irq_num)
1606  {
1607      int retval;
1608  
1609      rtapi_mutex_get(&(rtapi_data->mutex));
1610      retval = irq_delete(irq_num);
1611      rtapi_mutex_give(&(rtapi_data->mutex));
1612      return retval;
1613  }
1614  
1615  static int irq_delete(unsigned int irq_num)
1616  {
1617      int n, retval;
1618      int irq_id;
1619      irq_data *irq;
1620  
1621      /* validate irq */
1622      if ((irq_num < 1) || (irq_num > 255)) {
1623  	return -EINVAL;
1624      }
1625      /* check if a handler exists for this irq */
1626      n = 1;
1627      while ((n <= RTAPI_MAX_IRQS) && (irq_array[n].irq_num != irq_num)) {
1628  	n++;
1629      }
1630      if (n > RTAPI_MAX_IRQS) {
1631  	/* not found */
1632  	return -EINVAL;
1633      }
1634      /* found the irq */
1635      irq_id = n;
1636      irq = &(irq_array[n]);
1637      /* get rid of the handler */
1638      rt_shutdown_irq(irq_num);
1639      retval = rt_free_global_irq(irq_num);
1640      if (retval != 0) {
1641  	return -EINVAL;
1642      }
1643      /* update data */
1644      irq->irq_num = 0;
1645      irq->owner = 0;
1646      irq->handler = NULL;
1647      rtapi_data->irq_count--;
1648      rtapi_print_msg(RTAPI_MSG_DBG,
1649  	"RTAPI: handler for IRQ %d deleted\n", irq_num);
1650      return 0;
1651  }
1652  
1653  int rtapi_enable_interrupt(unsigned int irq)
1654  {
1655      rt_startup_irq(irq);
1656  
1657      return 0;
1658  }
1659  
1660  int rtapi_disable_interrupt(unsigned int irq)
1661  {
1662      rt_shutdown_irq(irq);
1663  
1664      return 0;
1665  }
1666  
1667  /***********************************************************************
1668  *                        I/O RELATED FUNCTIONS                         *
1669  ************************************************************************/
1670  
1671  void rtapi_outb(unsigned char byte, unsigned int port)
1672  {
1673      outb(byte, port);
1674  }
1675  
1676  unsigned char rtapi_inb(unsigned int port)
1677  {
1678      return inb(port);
1679  }
1680  
1681  int rtapi_is_realtime() { return 1; }
1682  int rtapi_is_kernelspace() { return 1; }
1683  
1684  /* starting with kernel 2.6, symbols that are used by other modules
1685     _must_ be explicitly exported.  2.4 and earlier kernels exported
1686     all non-static global symbols by default, so these explicit exports
1687     were not needed.  For 2.4 and older, you should define EXPORT_SYMTAB
1688     (before including module.h) to make these explicit exports work and 
1689     minimize pollution of the kernel namespace.  But EXPORT_SYMTAB
1690     must not be defined for 2.6, so the best place to do it is 
1691     probably in the makefiles somewhere (as a -D option to gcc).
1692  */
1693  
1694  EXPORT_SYMBOL(rtapi_init);
1695  EXPORT_SYMBOL(rtapi_exit);
1696  EXPORT_SYMBOL(rtapi_snprintf);
1697  EXPORT_SYMBOL(rtapi_vsnprintf);
1698  EXPORT_SYMBOL(rtapi_print);
1699  EXPORT_SYMBOL(rtapi_print_msg);
1700  EXPORT_SYMBOL(rtapi_set_msg_level);
1701  EXPORT_SYMBOL(rtapi_get_msg_level);
1702  EXPORT_SYMBOL(rtapi_set_msg_handler);
1703  EXPORT_SYMBOL(rtapi_get_msg_handler);
1704  EXPORT_SYMBOL(rtapi_clock_set_period);
1705  EXPORT_SYMBOL(rtapi_get_time);
1706  EXPORT_SYMBOL(rtapi_get_clocks);
1707  EXPORT_SYMBOL(rtapi_delay);
1708  EXPORT_SYMBOL(rtapi_delay_max);
1709  EXPORT_SYMBOL(rtapi_prio_highest);
1710  EXPORT_SYMBOL(rtapi_prio_lowest);
1711  EXPORT_SYMBOL(rtapi_prio_next_higher);
1712  EXPORT_SYMBOL(rtapi_prio_next_lower);
1713  EXPORT_SYMBOL(rtapi_task_new);
1714  EXPORT_SYMBOL(rtapi_task_delete);
1715  EXPORT_SYMBOL(rtapi_task_start);
1716  EXPORT_SYMBOL(rtapi_wait);
1717  EXPORT_SYMBOL(rtapi_task_resume);
1718  EXPORT_SYMBOL(rtapi_task_pause);
1719  EXPORT_SYMBOL(rtapi_task_self);
1720  EXPORT_SYMBOL(rtapi_shmem_new);
1721  EXPORT_SYMBOL(rtapi_shmem_delete);
1722  EXPORT_SYMBOL(rtapi_shmem_getptr);
1723  EXPORT_SYMBOL(rtapi_sem_new);
1724  EXPORT_SYMBOL(rtapi_sem_delete);
1725  EXPORT_SYMBOL(rtapi_sem_give);
1726  EXPORT_SYMBOL(rtapi_sem_take);
1727  EXPORT_SYMBOL(rtapi_sem_try);
1728  EXPORT_SYMBOL(rtapi_fifo_new);
1729  EXPORT_SYMBOL(rtapi_fifo_delete);
1730  EXPORT_SYMBOL(rtapi_fifo_read);
1731  EXPORT_SYMBOL(rtapi_fifo_write);
1732  EXPORT_SYMBOL(rtapi_irq_new);
1733  EXPORT_SYMBOL(rtapi_irq_delete);
1734  EXPORT_SYMBOL(rtapi_enable_interrupt);
1735  EXPORT_SYMBOL(rtapi_disable_interrupt);
1736  EXPORT_SYMBOL(rtapi_outb);
1737  EXPORT_SYMBOL(rtapi_inb);
1738  EXPORT_SYMBOL(rtapi_is_realtime);
1739  EXPORT_SYMBOL(rtapi_is_kernelspace);