rtai_ulapi.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_ulapi.c 6 * This file, 'rtai_ulapi.c', implements the nonrealtime 7 * portion of the API for the RTAI platform. 8 * 9 * Author: John Kasunich, Paul Corner 10 * License: LGPL Version 2 11 * 12 * Copyright (c) 2004 All rights reserved. 13 * 14 * Last change: 15 ********************************************************************/ 16 17 /** This file, 'rtai_ulapi.c', implements the non-realtime portion of 18 the API for the RTAI platform. The API is defined in rtapi.h, 19 which includes documentation for all the API functions. The 20 realtime portion of the API is implemented in rtai_rtapi.c 21 (for the RTAI platform). 22 */ 23 24 /** Copyright (C) 2003 John Kasunich 25 <jmkasunich AT users DOT sourceforge DOT net> 26 Copyright (C) 2003 Paul Corner 27 <paul_c AT users DOT sourceforge DOT net> 28 This library is based on version 1.0, which was released into 29 the public domain by its author, Fred Proctor. Thanks Fred! 30 */ 31 32 /* This library is free software; you can redistribute it and/or 33 modify it under the terms of version 2.1 of the GNU Lesser General 34 Public License as published by the Free Software Foundation. 35 This library is distributed in the hope that it will be useful, 36 but WITHOUT ANY WARRANTY; without even the implied warranty of 37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 GNU Lesser General Public License for more details. 39 40 You should have received a copy of the GNU General Lesser Public 41 License along with this library; if not, write to the Free Software 42 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 43 */ 44 45 /** THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR 46 ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE 47 TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of 48 harming persons must have provisions for completely removing power 49 from all motors, etc, before persons enter any danger area. All 50 machinery must be designed to comply with local and national safety 51 codes, and the authors of this software can not, and do not, take 52 any responsibility for such compliance. 53 54 This code was written as part of the EMC HAL project. For more 55 information, go to www.linuxcnc.org. 56 */ 57 58 #define _GNU_SOURCE 59 60 #include <stdio.h> /* sprintf() */ 61 #include <string.h> /* strcpy, etc. */ 62 #include <stddef.h> /* NULL, needed for rtai_shm.h */ 63 #include <stdarg.h> /* va_arg, etc. */ 64 #include <unistd.h> /* open(), close() */ 65 #include <sys/mman.h> /* PROT_READ, needed for rtai_shm.h */ 66 #include <sys/types.h> /* off_t, needed for rtai_shm.h */ 67 #include <sys/fcntl.h> /* O_RDWR, needed for rtai_shm.h */ 68 #include "rtapi_rtai_shm_wrap.h" /*rtai_malloc,free() */ 69 #include <malloc.h> /* malloc(), free() */ 70 #include <sys/io.h> /* inb(), outb() */ 71 #include <errno.h> /* errno */ 72 73 #include "rtapi.h" /* public RTAPI decls */ 74 #include <rtapi_mutex.h> 75 #include "rtapi_common.h" /* shared realtime/nonrealtime stuff */ 76 77 /* the following are internal functions that do the real work associated 78 with deleting resources. They do not check the mutex that protects 79 the internal data structures. When someone calls a rtapi_xxx_delete() 80 function, the ulapi funct gets the mutex before calling one of these 81 internal functions. When internal code that already has the mutex 82 needs to delete something, it calls these functions directly. 83 */ 84 85 static int shmem_delete(int shmem_id, int module_id); 86 static int fifo_delete(int fifo_id, int module_id); 87 88 /* resource data unique to this process */ 89 static void *shmem_addr_array[RTAPI_MAX_SHMEMS + 1]; 90 static int fifo_fd_array[RTAPI_MAX_FIFOS + 1]; 91 92 static int msg_level = RTAPI_MSG_ERR; /* message printing level */ 93 94 static void check_memlock_limit(const char *where); 95 96 static int nummods; 97 /*********************************************************************** 98 * GENERAL PURPOSE FUNCTIONS * 99 ************************************************************************/ 100 101 int rtapi_init(const char *modname) 102 { 103 int n, module_id; 104 module_data *module; 105 106 /* say hello */ 107 rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: initing module %s\n", modname); 108 /* get shared memory block from OS and save its address */ 109 errno = 0; 110 if(!rtapi_data) 111 rtapi_data = rtai_malloc(RTAPI_KEY, sizeof(rtapi_data_t)); 112 // the check for -1 here is because rtai_malloc (in at least 113 // rtai 3.6.1, and probably others) has a bug where it 114 // sometimes returns -1 on error 115 if (rtapi_data == NULL || rtapi_data == (rtapi_data_t*)-1) { 116 rtapi_print_msg(RTAPI_MSG_ERR, 117 "RTAPI: ERROR: could not open shared memory (%s)\n", strerror(errno)); 118 check_memlock_limit("could not open shared memory"); 119 rtapi_data = 0; 120 return -ENOMEM; 121 } 122 nummods++; 123 /* perform a global init if needed */ 124 init_rtapi_data(rtapi_data); 125 /* check revision code */ 126 if (rtapi_data->rev_code != rev_code) { 127 /* mismatch - release master shared memory block */ 128 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: version mismatch %d vs %d\n", rtapi_data->rev_code, rev_code); 129 return -EINVAL; 130 } 131 /* set up local pointers to global data */ 132 module_array = rtapi_data->module_array; 133 task_array = rtapi_data->task_array; 134 shmem_array = rtapi_data->shmem_array; 135 sem_array = rtapi_data->sem_array; 136 fifo_array = rtapi_data->fifo_array; 137 irq_array = rtapi_data->irq_array; 138 /* perform local init */ 139 for (n = 0; n <= RTAPI_MAX_SHMEMS; n++) { 140 shmem_addr_array[n] = NULL; 141 } 142 143 /* get the mutex */ 144 rtapi_mutex_get(&(rtapi_data->mutex)); 145 /* find empty spot in module array */ 146 n = 1; 147 while ((n <= RTAPI_MAX_MODULES) && (module_array[n].state != NO_MODULE)) { 148 n++; 149 } 150 if (n > RTAPI_MAX_MODULES) { 151 /* no room */ 152 rtapi_mutex_give(&(rtapi_data->mutex)); 153 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: reached module limit %d\n", 154 n); 155 return -EMFILE; 156 } 157 /* we have space for the module */ 158 module_id = n; 159 module = &(module_array[n]); 160 /* update module data */ 161 module->state = USERSPACE; 162 if (modname != NULL) { 163 /* use name supplied by caller, truncating if needed */ 164 snprintf(module->name, RTAPI_NAME_LEN, "%s", modname); 165 } else { 166 /* make up a name */ 167 snprintf(module->name, RTAPI_NAME_LEN, "ULMOD%03d", module_id); 168 } 169 rtapi_data->ul_module_count++; 170 rtapi_mutex_give(&(rtapi_data->mutex)); 171 rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module '%s' inited, ID = %02d\n", 172 module->name, module_id); 173 return module_id; 174 } 175 176 int rtapi_exit(int module_id) 177 { 178 module_data *module; 179 int n; 180 181 if (rtapi_data == NULL) { 182 rtapi_print_msg(RTAPI_MSG_ERR, 183 "RTAPI: ERROR: exit called before init\n"); 184 return -EINVAL; 185 } 186 rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %02d exiting\n", module_id); 187 /* validate module ID */ 188 if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { 189 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: bad module id\n"); 190 return -EINVAL; 191 } 192 /* get mutex */ 193 rtapi_mutex_get(&(rtapi_data->mutex)); 194 /* point to the module's data */ 195 module = &(module_array[module_id]); 196 /* check module status */ 197 if (module->state != USERSPACE) { 198 rtapi_print_msg(RTAPI_MSG_ERR, 199 "RTAPI: ERROR: not a userspace module\n"); 200 rtapi_mutex_give(&(rtapi_data->mutex)); 201 return -EINVAL; 202 } 203 /* clean up any mess left behind by the module */ 204 for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) { 205 if (test_bit(module_id, shmem_array[n].bitmap)) { 206 fprintf(stderr, 207 "ULAPI: WARNING: module '%s' failed to delete shmem %02d\n", 208 module->name, n); 209 shmem_delete(n, module_id); 210 } 211 } 212 for (n = 1; n <= RTAPI_MAX_FIFOS; n++) { 213 if ((fifo_array[n].reader == module_id) || 214 (fifo_array[n].writer == module_id)) { 215 fprintf(stderr, 216 "ULAPI: WARNING: module '%s' failed to delete fifo %02d\n", 217 module->name, n); 218 fifo_delete(n, module_id); 219 } 220 } 221 /* update module data */ 222 rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: module %02d exited, name = '%s'\n", 223 module_id, module->name); 224 module->state = NO_MODULE; 225 module->name[0] = '\0'; 226 rtapi_data->ul_module_count--; 227 rtapi_mutex_give(&(rtapi_data->mutex)); 228 nummods--; 229 if(nummods == 0) 230 { 231 rtai_free(RTAPI_KEY, rtapi_data); 232 rtapi_data = 0; 233 } 234 return 0; 235 } 236 237 int rtapi_vsnprintf(char *buf, unsigned long int size, const char *fmt, va_list ap) { 238 return vsnprintf(buf, size, fmt, ap); 239 } 240 241 int rtapi_snprintf(char *buf, unsigned long int size, const char *fmt, ...) 242 { 243 va_list args; 244 int i; 245 246 va_start(args, fmt); 247 /* call the normal library vnsprintf() */ 248 i = vsnprintf(buf, size, fmt, args); 249 va_end(args); 250 return i; 251 } 252 253 #define BUFFERLEN 1024 254 255 void rtapi_print(const char *fmt, ...) 256 { 257 char buffer[BUFFERLEN + 1]; 258 va_list args; 259 260 va_start(args, fmt); 261 /* call the normal library vnsprintf() */ 262 vsnprintf(buffer, BUFFERLEN, fmt, args); 263 fputs(buffer, stdout); 264 va_end(args); 265 } 266 267 void rtapi_print_msg(msg_level_t level, const char *fmt, ...) 268 { 269 va_list args; 270 271 if ((level <= msg_level) && (msg_level != RTAPI_MSG_NONE)) { 272 va_start(args, fmt); 273 vfprintf(stderr, fmt, args); 274 va_end(args); 275 } 276 } 277 278 int rtapi_set_msg_level(int level) 279 { 280 if ((level < RTAPI_MSG_NONE) || (level > RTAPI_MSG_ALL)) { 281 return -EINVAL; 282 } 283 msg_level = level; 284 return 0; 285 } 286 287 int rtapi_get_msg_level(void) 288 { 289 return msg_level; 290 } 291 292 void rtapi_printall(void) 293 { 294 module_data *modules; 295 task_data *tasks; 296 shmem_data *shmems; 297 sem_data *sems; 298 fifo_data *fifos; 299 irq_data *irqs; 300 int n, m; 301 302 if (rtapi_data == NULL) { 303 printf("rtapi_data = NULL, not initialized\n"); 304 return; 305 } 306 printf("rtapi_data = %p\n", rtapi_data); 307 printf(" magic = %d\n", rtapi_data->magic); 308 printf(" rev_code = %08x\n", rtapi_data->rev_code); 309 printf(" mutex = %lu\n", rtapi_data->mutex); 310 printf(" rt_module_count = %d\n", rtapi_data->rt_module_count); 311 printf(" ul_module_count = %d\n", rtapi_data->ul_module_count); 312 printf(" task_count = %d\n", rtapi_data->task_count); 313 printf(" shmem_count = %d\n", rtapi_data->shmem_count); 314 printf(" sem_count = %d\n", rtapi_data->sem_count); 315 printf(" fifo_count = %d\n", rtapi_data->fifo_count); 316 printf(" irq_countc = %d\n", rtapi_data->irq_count); 317 printf(" timer_running = %d\n", rtapi_data->timer_running); 318 printf(" timer_period = %ld\n", rtapi_data->timer_period); 319 modules = &(rtapi_data->module_array[0]); 320 tasks = &(rtapi_data->task_array[0]); 321 shmems = &(rtapi_data->shmem_array[0]); 322 sems = &(rtapi_data->sem_array[0]); 323 fifos = &(rtapi_data->fifo_array[0]); 324 irqs = &(rtapi_data->irq_array[0]); 325 printf(" module array = %p\n", modules); 326 printf(" task array = %p\n", tasks); 327 printf(" shmem array = %p\n", shmems); 328 printf(" sem array = %p\n", sems); 329 printf(" fifo array = %p\n", fifos); 330 printf(" irq array = %p\n", irqs); 331 for (n = 0; n <= RTAPI_MAX_MODULES; n++) { 332 if (modules[n].state != NO_MODULE) { 333 printf(" module %02d\n", n); 334 printf(" state = %d\n", modules[n].state); 335 printf(" name = %p\n", modules[n].name); 336 printf(" name = '%s'\n", modules[n].name); 337 } 338 } 339 for (n = 0; n <= RTAPI_MAX_TASKS; n++) { 340 if (tasks[n].state != EMPTY) { 341 printf(" task %02d\n", n); 342 printf(" state = %d\n", tasks[n].state); 343 printf(" prio = %d\n", tasks[n].prio); 344 printf(" owner = %d\n", tasks[n].owner); 345 printf(" code = %p\n", tasks[n].taskcode); 346 } 347 } 348 for (n = 0; n <= RTAPI_MAX_SHMEMS; n++) { 349 if (shmems[n].key != 0) { 350 printf(" shmem %02d\n", n); 351 printf(" key = %d\n", shmems[n].key); 352 printf(" rtusers = %d\n", shmems[n].rtusers); 353 printf(" ulusers = %d\n", shmems[n].ulusers); 354 printf(" size = %ld\n", shmems[n].size); 355 printf(" bitmap = "); 356 for (m = 0; m <= RTAPI_MAX_MODULES; m++) { 357 if (test_bit(m, shmems[n].bitmap)) { 358 putchar('1'); 359 } else { 360 putchar('0'); 361 } 362 } 363 putchar('\n'); 364 } 365 } 366 for (n = 0; n <= RTAPI_MAX_SEMS; n++) { 367 if (sems[n].key != 0) { 368 printf(" sem %02d\n", n); 369 printf(" key = %d\n", sems[n].key); 370 printf(" users = %d\n", sems[n].users); 371 printf(" bitmap = "); 372 for (m = 0; m <= RTAPI_MAX_MODULES; m++) { 373 if (test_bit(m, sems[n].bitmap)) { 374 putchar('1'); 375 } else { 376 putchar('0'); 377 } 378 } 379 putchar('\n'); 380 } 381 } 382 for (n = 0; n <= RTAPI_MAX_FIFOS; n++) { 383 if (fifos[n].state != UNUSED) { 384 printf(" fifo %02d\n", n); 385 printf(" state = %d\n", fifos[n].state); 386 printf(" key = %d\n", fifos[n].key); 387 printf(" reader = %d\n", fifos[n].reader); 388 printf(" writer = %d\n", fifos[n].writer); 389 printf(" size = %ld\n", fifos[n].size); 390 } 391 } 392 for (n = 0; n <= RTAPI_MAX_IRQS; n++) { 393 if (irqs[n].irq_num != 0) { 394 printf(" irq %02d\n", n); 395 printf(" irq_num = %d\n", irqs[n].irq_num); 396 printf(" owner = %d\n", irqs[n].owner); 397 printf(" handler = %p\n", irqs[n].handler); 398 } 399 } 400 } 401 402 /*********************************************************************** 403 * SHARED MEMORY RELATED FUNCTIONS * 404 ************************************************************************/ 405 406 int rtapi_shmem_new(int key, int module_id, unsigned long int size) 407 { 408 int n; 409 int shmem_id; 410 shmem_data *shmem; 411 412 /* key must be non-zero, and also cannot match the key that RTAPI uses */ 413 if ((key == 0) || (key == RTAPI_KEY)) { 414 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: bad shmem key: %d\n", 415 key); 416 return -EINVAL; 417 } 418 /* get the mutex */ 419 rtapi_mutex_get(&(rtapi_data->mutex)); 420 /* validate module_id */ 421 if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { 422 rtapi_mutex_give(&(rtapi_data->mutex)); 423 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: bad module ID: %d\n", 424 module_id); 425 return -EINVAL; 426 } 427 if (module_array[module_id].state != USERSPACE) { 428 rtapi_print_msg(RTAPI_MSG_ERR, 429 "RTAPI: ERROR: not a user space module ID: %d\n", module_id); 430 rtapi_mutex_give(&(rtapi_data->mutex)); 431 return -EINVAL; 432 } 433 /* check if a block is already open for this key */ 434 for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) { 435 if (shmem_array[n].key == key) { 436 /* found a match */ 437 shmem_id = n; 438 shmem = &(shmem_array[n]); 439 /* is it big enough? */ 440 if (shmem->size < size) { 441 rtapi_mutex_give(&(rtapi_data->mutex)); 442 rtapi_print_msg(RTAPI_MSG_ERR, 443 "RTAPI: ERROR: shmem size mismatch\n"); 444 return -EINVAL; 445 } 446 /* is this module already using it? */ 447 if (test_bit(module_id, shmem->bitmap)) { 448 rtapi_mutex_give(&(rtapi_data->mutex)); 449 rtapi_print_msg(RTAPI_MSG_ERR, 450 "RTAPI: Warning: shmem already mapped\n"); 451 return -EINVAL; 452 } 453 /* no, map it */ 454 shmem_addr_array[shmem_id] = rtai_malloc(key, shmem->size); 455 // the check for -1 here is because rtai_malloc (in at least 456 // rtai 3.6.1, and probably others) has a bug where it 457 // sometimes returns -1 on error 458 if (shmem_addr_array[shmem_id] == NULL || shmem_addr_array[shmem_id] == (void*)-1) { 459 /* map failed */ 460 rtapi_print_msg(RTAPI_MSG_ERR, 461 "RTAPI: ERROR: failed to map shmem\n"); 462 rtapi_mutex_give(&(rtapi_data->mutex)); 463 check_memlock_limit("failed to map shmem"); 464 return -ENOMEM; 465 } 466 /* update usage data */ 467 set_bit(module_id, shmem->bitmap); 468 shmem->ulusers++; 469 /* done */ 470 rtapi_mutex_give(&(rtapi_data->mutex)); 471 return shmem_id; 472 } 473 } 474 /* find empty spot in shmem array */ 475 n = 1; 476 while ((n <= RTAPI_MAX_SHMEMS) && (shmem_array[n].key != 0)) { 477 n++; 478 } 479 if (n > RTAPI_MAX_SHMEMS) { 480 /* no room */ 481 rtapi_mutex_give(&(rtapi_data->mutex)); 482 rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: reached shmem limit %d\n", 483 n); 484 return -EMFILE; 485 } 486 /* we have space for the block data */ 487 shmem_id = n; 488 shmem = &(shmem_array[n]); 489 /* now get shared memory block from OS and save its address */ 490 shmem_addr_array[shmem_id] = rtai_malloc(key, size); 491 // the check for -1 here is because rtai_malloc (in at least 492 // rtai 3.6.1, and probably others) has a bug where it 493 // sometimes returns -1 on error 494 if (shmem_addr_array[shmem_id] == NULL || shmem_addr_array[shmem_id] == (void*)-1) { 495 rtapi_mutex_give(&(rtapi_data->mutex)); 496 rtapi_print_msg(RTAPI_MSG_ERR, 497 "RTAPI: ERROR: could not create shmem %d\n", n); 498 return -ENOMEM; 499 } 500 /* the block has been created, update data */ 501 set_bit(module_id, shmem->bitmap); 502 shmem->key = key; 503 shmem->rtusers = 0; 504 shmem->ulusers = 1; 505 shmem->size = size; 506 rtapi_data->shmem_count++; 507 /* zero the first word of the shmem area */ 508 *((long int *) (shmem_addr_array[shmem_id])) = 0; 509 /* done */ 510 rtapi_mutex_give(&(rtapi_data->mutex)); 511 return shmem_id; 512 } 513 514 #include <sys/time.h> 515 #include <sys/resource.h> 516 #define RECOMMENDED (20480*1024lu) 517 static void check_memlock_limit(const char *where) { 518 static int checked=0; 519 struct rlimit lim; 520 int result; 521 if(checked) return; 522 checked=1; 523 524 result = getrlimit(RLIMIT_MEMLOCK, &lim); 525 if(result < 0) { perror("getrlimit"); return; } 526 if(lim.rlim_cur == (rlim_t)-1) return; // unlimited 527 if(lim.rlim_cur >= RECOMMENDED) return; // limit is at least recommended 528 rtapi_print_msg(RTAPI_MSG_ERR, 529 "RTAPI: Locked memory limit is %luKiB, recommended at least %luKiB.\n" 530 "This can cause the error '%s'.\n" 531 "For more information, see\n" 532 "\thttp://wiki.linuxcnc.org/cgi-bin/emcinfo.pl?LockedMemory\n", 533 (unsigned long)lim.rlim_cur/1024, RECOMMENDED/1024, where); 534 return; 535 } 536 537 int rtapi_shmem_delete(int shmem_id, int module_id) 538 { 539 int retval; 540 541 rtapi_mutex_get(&(rtapi_data->mutex)); 542 retval = shmem_delete(shmem_id, module_id); 543 rtapi_mutex_give(&(rtapi_data->mutex)); 544 return retval; 545 } 546 547 int shmem_delete(int shmem_id, int module_id) 548 { 549 shmem_data *shmem; 550 551 /* validate shmem ID */ 552 if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) { 553 return -EINVAL; 554 } 555 /* point to the shmem's data */ 556 shmem = &(shmem_array[shmem_id]); 557 /* is the block valid? */ 558 if (shmem->key == 0) { 559 return -EINVAL; 560 } 561 /* validate module_id */ 562 if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { 563 return -EINVAL; 564 } 565 if (module_array[module_id].state != USERSPACE) { 566 return -EINVAL; 567 } 568 /* is this module using the block? */ 569 if (test_bit(module_id, shmem->bitmap) == 0) { 570 return -EINVAL; 571 } 572 /* OK, we're no longer using it */ 573 clear_bit(module_id, shmem->bitmap); 574 shmem->ulusers--; 575 /* unmap the block */ 576 rtai_free(shmem->key, shmem_addr_array[shmem_id]); 577 shmem_addr_array[shmem_id] = NULL; 578 /* is somebody else still using the block? */ 579 if ((shmem->ulusers > 0) || (shmem->rtusers > 0)) { 580 /* yes, we're done for now */ 581 return 0; 582 } 583 /* update the data array and usage count */ 584 shmem->key = 0; 585 shmem->size = 0; 586 rtapi_data->shmem_count--; 587 return 0; 588 } 589 590 int rtapi_shmem_getptr(int shmem_id, void **ptr) 591 { 592 /* validate shmem ID */ 593 if ((shmem_id < 1) || (shmem_id > RTAPI_MAX_SHMEMS)) { 594 return -EINVAL; 595 } 596 /* is the block mapped? */ 597 if (shmem_addr_array[shmem_id] == NULL) { 598 return -EINVAL; 599 } 600 /* pass memory address back to caller */ 601 *ptr = shmem_addr_array[shmem_id]; 602 return 0; 603 } 604 605 /*********************************************************************** 606 * FIFO RELATED FUNCTIONS * 607 ************************************************************************/ 608 609 int rtapi_fifo_new(int key, int module_id, unsigned long int size, char mode) 610 { 611 enum { DEVSTR_LEN = 256 }; 612 char devstr[DEVSTR_LEN]; 613 int n, flags; 614 int fifo_id; 615 fifo_data *fifo; 616 617 /* key must be non-zero */ 618 if (key == 0) { 619 return -EINVAL; 620 } 621 /* mode must be "R" or "W" */ 622 if ((mode != 'R') && (mode != 'W')) { 623 return -EINVAL; 624 } 625 /* determine mode for fifo */ 626 if (mode == 'R') { 627 flags = O_RDONLY; 628 } else { /* mode == 'W' */ 629 630 flags = O_WRONLY; 631 } 632 /* get the mutex */ 633 rtapi_mutex_get(&(rtapi_data->mutex)); 634 /* validate module_id */ 635 if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { 636 rtapi_mutex_give(&(rtapi_data->mutex)); 637 return -EINVAL; 638 } 639 if (module_array[module_id].state != USERSPACE) { 640 rtapi_mutex_give(&(rtapi_data->mutex)); 641 return -EINVAL; 642 } 643 /* check if a fifo already exists for this key */ 644 for (n = 1; n <= RTAPI_MAX_FIFOS; n++) { 645 if ((fifo_array[n].state != UNUSED) && (fifo_array[n].key == key)) { 646 /* found a match */ 647 fifo_id = n; 648 fifo = &(fifo_array[n]); 649 /* is the desired mode available */ 650 if (mode == 'R') { 651 if (fifo->state & HAS_READER) { 652 rtapi_mutex_give(&(rtapi_data->mutex)); 653 return -EBUSY; 654 } 655 /* determine system name for fifo */ 656 sprintf(devstr, "/dev/rtf%d", fifo_id); 657 /* open the fifo */ 658 fifo_fd_array[fifo_id] = open(devstr, flags); 659 if (fifo_fd_array[fifo_id] < 0) { 660 /* open failed */ 661 rtapi_mutex_give(&(rtapi_data->mutex)); 662 return -ENOENT; 663 } 664 /* fifo opened, update status */ 665 fifo->state |= HAS_READER; 666 fifo->reader = module_id; 667 rtapi_mutex_give(&(rtapi_data->mutex)); 668 return fifo_id; 669 } else { /* mode == 'W' */ 670 671 if (fifo->state & HAS_WRITER) { 672 rtapi_mutex_give(&(rtapi_data->mutex)); 673 return -EBUSY; 674 } 675 /* determine system name for fifo */ 676 sprintf(devstr, "/dev/rtf%d", fifo_id); 677 /* open the fifo */ 678 fifo_fd_array[fifo_id] = open(devstr, flags); 679 if (fifo_fd_array[fifo_id] < 0) { 680 /* open failed */ 681 rtapi_mutex_give(&(rtapi_data->mutex)); 682 return -ENOENT; 683 } 684 /* fifo opened, update status */ 685 fifo->state |= HAS_WRITER; 686 fifo->writer = module_id; 687 rtapi_mutex_give(&(rtapi_data->mutex)); 688 return fifo_id; 689 } 690 } 691 } 692 /* find empty spot in fifo array */ 693 n = 1; 694 while ((n <= RTAPI_MAX_FIFOS) && (fifo_array[n].state != UNUSED)) { 695 n++; 696 } 697 if (n > RTAPI_MAX_FIFOS) { 698 /* no room */ 699 rtapi_mutex_give(&(rtapi_data->mutex)); 700 return -EMFILE; 701 } 702 /* we have a free ID for the fifo */ 703 fifo_id = n; 704 fifo = &(fifo_array[n]); 705 /* determine system name for fifo */ 706 sprintf(devstr, "/dev/rtf%d", fifo_id); 707 /* open the fifo */ 708 fifo_fd_array[fifo_id] = open(devstr, flags); 709 if (fifo_fd_array[fifo_id] < 0) { 710 /* open failed */ 711 rtapi_mutex_give(&(rtapi_data->mutex)); 712 return -ENOENT; 713 } 714 /* the fifo has been created, update data */ 715 if (mode == 'R') { 716 fifo->state = HAS_READER; 717 fifo->reader = module_id; 718 } else { /* mode == 'W' */ 719 720 fifo->state = HAS_WRITER; 721 fifo->writer = module_id; 722 } 723 fifo->key = key; 724 fifo->size = size; 725 rtapi_data->fifo_count++; 726 /* done */ 727 rtapi_mutex_give(&(rtapi_data->mutex)); 728 return fifo_id; 729 } 730 731 int rtapi_fifo_delete(int fifo_id, int module_id) 732 { 733 int retval; 734 735 rtapi_mutex_get(&(rtapi_data->mutex)); 736 retval = fifo_delete(fifo_id, module_id); 737 rtapi_mutex_give(&(rtapi_data->mutex)); 738 return retval; 739 } 740 741 static int fifo_delete(int fifo_id, int module_id) 742 { 743 fifo_data *fifo; 744 745 /* validate fifo ID */ 746 if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) { 747 return -EINVAL; 748 } 749 /* point to the fifo's data */ 750 fifo = &(fifo_array[fifo_id]); 751 /* is the fifo valid? */ 752 if (fifo->state == UNUSED) { 753 return -EINVAL; 754 } 755 /* validate module_id */ 756 if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { 757 return -EINVAL; 758 } 759 if (module_array[module_id].state != USERSPACE) { 760 return -EINVAL; 761 } 762 /* is this module using the fifo? */ 763 if ((fifo->reader != module_id) && (fifo->writer != module_id)) { 764 return -EINVAL; 765 } 766 /* update fifo state */ 767 if (fifo->reader == module_id) { 768 fifo->state &= ~HAS_READER; 769 fifo->reader = 0; 770 } 771 if (fifo->writer == module_id) { 772 fifo->state &= ~HAS_WRITER; 773 fifo->writer = 0; 774 } 775 /* close the fifo */ 776 if (close(fifo_id) < 0) { 777 return -ENOENT; 778 } 779 /* is somebody else still using the fifo */ 780 if (fifo->state != UNUSED) { 781 /* yes, done for now */ 782 return 0; 783 } 784 /* no other users, update the data array and usage count */ 785 fifo->state = UNUSED; 786 fifo->key = 0; 787 fifo->size = 0; 788 rtapi_data->fifo_count--; 789 return 0; 790 } 791 792 int rtapi_fifo_read(int fifo_id, char *buf, unsigned long int size) 793 { 794 int retval; 795 796 fifo_data *fifo; 797 798 /* validate fifo ID */ 799 if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) { 800 return -EINVAL; 801 } 802 /* point to the fifo's data */ 803 fifo = &(fifo_array[fifo_id]); 804 /* is the fifo valid? */ 805 if ((fifo->state & HAS_READER) == 0) { 806 return -EINVAL; 807 } 808 /* get whatever data is available */ 809 retval = read(fifo_fd_array[fifo_id], buf, size); 810 if (retval <= 0) { 811 return -EINVAL; 812 } 813 return retval; 814 815 } 816 817 int rtapi_fifo_write(int fifo_id, char *buf, unsigned long int size) 818 { 819 int retval; 820 fifo_data *fifo; 821 822 /* validate fifo ID */ 823 if ((fifo_id < 1) || (fifo_id > RTAPI_MAX_FIFOS)) { 824 return -EINVAL; 825 } 826 /* point to the fifo's data */ 827 fifo = &(fifo_array[fifo_id]); 828 /* is the fifo valid? */ 829 if ((fifo->state & HAS_WRITER) == 0) { 830 return -EINVAL; 831 } 832 /* put whatever data will fit */ 833 retval = write(fifo_fd_array[fifo_id], buf, size); 834 if (retval < 0) { 835 return -EINVAL; 836 } 837 return retval; 838 } 839 840 /*********************************************************************** 841 * I/O RELATED FUNCTIONS * 842 ************************************************************************/ 843 844 void rtapi_outb(unsigned char byte, unsigned int port) 845 { 846 outb(byte, port); 847 } 848 849 unsigned char rtapi_inb(unsigned int port) 850 { 851 return inb(port); 852 } 853 854 int rtapi_is_realtime() { return 1; } 855 int rtapi_is_kernelspace() { return 1; } 856 857 void rtapi_delay(long ns) { 858 if(ns > rtapi_delay_max()) ns = rtapi_delay_max(); 859 struct timespec ts = {0, ns}; 860 clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, 0); 861 } 862 863 long int rtapi_delay_max() { return 999999999; }