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);