drvlib.c
1 /** 2 * @file 3 * Real-Time Driver Model for RTAI, driver library 4 * 5 * @note Copyright (C) 2005-2007 Jan Kiszka <jan.kiszka@web.de> 6 * @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net> 7 * @note Copyright (C) 2008 Gilles Chanteperdrix <gilles.chanteperdrix@gmail.com> 8 * 9 * with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it> 10 * 11 * RTAI is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * RTAI is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with RTAI; if not, write to the Free Software Foundation, 23 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 */ 25 26 /*! 27 * @ingroup rtdm 28 * @defgroup driverapi Driver Development API 29 * 30 * This is the lower interface of RTDM provided to device drivers, currently 31 * limited to kernel-space. Real-time drivers should only use functions of 32 * this interface in order to remain portable. 33 */ 34 35 #include <linux/bitops.h> 36 #include <asm/page.h> 37 #include <asm/io.h> 38 #include <asm/pgtable.h> 39 #include <linux/delay.h> 40 #include <linux/mman.h> 41 #include <linux/highmem.h> 42 43 #include <rtdm/rtdm_driver.h> 44 45 /*! 46 * @ingroup driverapi 47 * @defgroup clock Clock Services 48 * @{ 49 */ 50 51 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 52 /** 53 * @brief Get system time 54 * 55 * @return The system time in nanoseconds is returned 56 * 57 * @note The resolution of this service depends on the system timer. In 58 * particular, if the system timer is running in periodic mode, the return 59 * value will be limited to multiples of the timer tick period. 60 * 61 * @note The system timer may have to be started to obtain valid results. 62 * Whether this happens automatically or is controlled by the 63 * application (as with RTAI) depends on the RTDM host environment. 64 * 65 * Environments: 66 * 67 * This service can be called from: 68 * 69 * - Kernel module initialization/cleanup code 70 * - Interrupt service routine 71 * - Kernel-based task 72 * - User-space task (RT, non-RT) 73 * 74 * Rescheduling: never. 75 */ 76 nanosecs_abs_t rtdm_clock_read(void); 77 78 /** 79 * @brief Get monotonic time 80 * 81 * @return The monotonic time in nanoseconds is returned 82 * 83 * @note The resolution of this service depends on the system timer. In 84 * particular, if the system timer is running in periodic mode, the return 85 * value will be limited to multiples of the timer tick period. 86 * 87 * @note The system timer may have to be started to obtain valid results. 88 * Whether this happens automatically or is controlled by the 89 * application (as with RTAI) depends on the RTDM host environment. 90 * 91 * Environments: 92 * 93 * This service can be called from: 94 * 95 * - Kernel module initialization/cleanup code 96 * - Interrupt service routine 97 * - Kernel-based task 98 * - User-space task (RT, non-RT) 99 * 100 * Rescheduling: never. 101 */ 102 nanosecs_abs_t rtdm_clock_read_monotonic(void); 103 #endif /* DOXYGEN_CPP */ 104 /** @} */ 105 106 /*! 107 * @ingroup driverapi 108 * @defgroup rtdmtask Task Services 109 * @{ 110 */ 111 112 /** 113 * @brief Intialise and start a real-time task 114 * 115 * After initialising a task, the task handle remains valid and can be passed 116 * to RTDM services until either rtdm_task_destroy() or rtdm_task_join_nrt() 117 * was invoked. 118 * 119 * @param[in,out] task Task handle 120 * @param[in] name Optional task name 121 * @param[in] task_proc Procedure to be executed by the task 122 * @param[in] arg Custom argument passed to @c task_proc() on entry 123 * @param[in] priority Priority of the task, see also 124 * @ref taskprio "Task Priority Range" 125 * @param[in] period Period in nanoseconds of a cyclic task, 0 for non-cyclic 126 * mode 127 * 128 * @return 0 on success, otherwise negative error code 129 * 130 * Environments: 131 * 132 * This service can be called from: 133 * 134 * - Kernel module initialization/cleanup code 135 * - Kernel-based task 136 * - User-space task (RT, non-RT) 137 * 138 * Rescheduling: possible. 139 */ 140 int rtdm_task_init_cpuid(rtdm_task_t *task, const char *name, 141 rtdm_task_proc_t task_proc, void *arg, 142 int priority, nanosecs_rel_t period, int cpuid) 143 { 144 char *lname; 145 if (rt_task_init_cpuid(task, (void *)task_proc, (long)arg, PAGE_SIZE, priority, 0, 0, cpuid)) { 146 return -ENOMEM; 147 } 148 if (period > 0) { 149 rt_task_make_periodic_relative_ns(task, 0, period); 150 } else { 151 rt_task_resume(task); 152 } 153 lname = (char *)((unsigned long)name + strlen(name) - 6); 154 rt_register(nam2num(lname > name ? lname : name), task, IS_TASK, 0); 155 return 0; 156 } 157 158 159 160 161 162 163 164 165 166 167 168 EXPORT_SYMBOL(rtdm_task_init_cpuid); 169 170 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 171 /** 172 * @brief Destroy a real-time task 173 * 174 * @param[in,out] task Task handle as returned by rtdm_task_init() 175 * 176 * @note Passing the same task handle to RTDM services after the completion of 177 * this function is not allowed. 178 * 179 * Environments: 180 * 181 * This service can be called from: 182 * 183 * - Kernel module initialization/cleanup code 184 * - Kernel-based task 185 * - User-space task (RT, non-RT) 186 * 187 * Rescheduling: never. 188 */ 189 void rtdm_task_destroy(rtdm_task_t *task); 190 191 /** 192 * @brief Adjust real-time task priority 193 * 194 * @param[in,out] task Task handle as returned by rtdm_task_init() 195 * @param[in] priority New priority of the task, see also 196 * @ref taskprio "Task Priority Range" 197 * 198 * Environments: 199 * 200 * This service can be called from: 201 * 202 * - Kernel module initialization/cleanup code 203 * - Interrupt service routine 204 * - Kernel-based task 205 * - User-space task (RT, non-RT) 206 * 207 * Rescheduling: possible. 208 */ 209 void rtdm_task_set_priority(rtdm_task_t *task, int priority); 210 211 /** 212 * @brief Adjust real-time task period 213 * 214 * @param[in,out] task Task handle as returned by rtdm_task_init() 215 * @param[in] period New period in nanoseconds of a cyclic task, 0 for 216 * non-cyclic mode 217 * 218 * Environments: 219 * 220 * This service can be called from: 221 * 222 * - Kernel module initialization/cleanup code 223 * - Interrupt service routine 224 * - Kernel-based task 225 * - User-space task (RT, non-RT) 226 * 227 * Rescheduling: possible. 228 */ 229 int rtdm_task_set_period(rtdm_task_t *task, nanosecs_rel_t period); 230 231 /** 232 * @brief Wait on next real-time task period 233 * 234 * @return 0 on success, otherwise: 235 * 236 * - -EINVAL is returned if calling task is not in periodic mode. 237 * 238 * - -ETIMEDOUT is returned if a timer overrun occurred, which indicates 239 * that a previous release point has been missed by the calling task. 240 * 241 * Environments: 242 * 243 * This service can be called from: 244 * 245 * - Kernel-based task 246 * - User-space task (RT) 247 * 248 * Rescheduling: always, unless a timer overrun occured. 249 */ 250 int rtdm_task_wait_period(void); 251 252 /** 253 * @brief Activate a blocked real-time task 254 * 255 * @return Non-zero is returned if the task was actually unblocked from a 256 * pending wait state, 0 otherwise. 257 * 258 * Environments: 259 * 260 * This service can be called from: 261 * 262 * - Kernel module initialization/cleanup code 263 * - Interrupt service routine 264 * - Kernel-based task 265 * - User-space task (RT, non-RT) 266 * 267 * Rescheduling: possible. 268 */ 269 int rtdm_task_unblock(rtdm_task_t *task); 270 271 /** 272 * @brief Get current real-time task 273 * 274 * @return Pointer to task handle 275 * 276 * Environments: 277 * 278 * This service can be called from: 279 * 280 * - Kernel-based task 281 * - User-space task (RT, non-RT) 282 * 283 * Rescheduling: never. 284 */ 285 rtdm_task_t *rtdm_task_current(void); 286 287 /** 288 * @brief Sleep a specified amount of time 289 * 290 * @param[in] delay Delay in nanoseconds, see @ref RTDM_TIMEOUT_xxx for 291 * special values. 292 * 293 * @return 0 on success, otherwise: 294 * 295 * - -EINTR is returned if calling task has been unblock by a signal or 296 * explicitly via rtdm_task_unblock(). 297 * 298 * - -EPERM @e may be returned if an illegal invocation environment is 299 * detected. 300 * 301 * Environments: 302 * 303 * This service can be called from: 304 * 305 * - Kernel-based task 306 * - User-space task (RT) 307 * 308 * Rescheduling: always. 309 */ 310 int rtdm_task_sleep(nanosecs_rel_t delay); 311 312 /** 313 * @brief Sleep until a specified absolute time 314 * 315 * @deprecated Use rtdm_task_sleep_abs instead! 316 * 317 * @param[in] wakeup_time Absolute timeout in nanoseconds 318 * 319 * @return 0 on success, otherwise: 320 * 321 * - -EINTR is returned if calling task has been unblock by a signal or 322 * explicitly via rtdm_task_unblock(). 323 * 324 * - -EPERM @e may be returned if an illegal invocation environment is 325 * detected. 326 * 327 * Environments: 328 * 329 * This service can be called from: 330 * 331 * - Kernel-based task 332 * - User-space task (RT) 333 * 334 * Rescheduling: always, unless the specified time already passed. 335 */ 336 int rtdm_task_sleep_until(nanosecs_abs_t wakeup_time); 337 338 /** 339 * @brief Sleep until a specified absolute time 340 * 341 * @param[in] wakeup_time Absolute timeout in nanoseconds 342 * @param[in] mode Selects the timer mode, see RTDM_TIMERMODE_xxx for details 343 * 344 * @return 0 on success, otherwise: 345 * 346 * - -EINTR is returned if calling task has been unblock by a signal or 347 * explicitly via rtdm_task_unblock(). 348 * 349 * - -EPERM @e may be returned if an illegal invocation environment is 350 * detected. 351 * 352 * - -EINVAL is returned if an invalid parameter was passed. 353 * 354 * Environments: 355 * 356 * This service can be called from: 357 * 358 * - Kernel-based task 359 * - User-space task (RT) 360 * 361 * Rescheduling: always, unless the specified time already passed. 362 */ 363 int rtdm_task_sleep_abs(nanosecs_abs_t wakeup_time, enum rtdm_timer_mode mode); 364 365 #endif /* DOXYGEN_CPP */ 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 /** 383 * @brief Wait on a real-time task to terminate 384 * 385 * @param[in,out] task Task handle as returned by rtdm_task_init() 386 * @param[in] poll_delay Delay in milliseconds between periodic tests for the 387 * state of the real-time task. This parameter is ignored if the termination 388 * is internally realised without polling. 389 * 390 * @note Passing the same task handle to RTDM services after the completion of 391 * this function is not allowed. 392 * 393 * @note This service does not trigger the termination of the targeted task. 394 * The user has to take of this, otherwise rtdm_task_join_nrt() will never 395 * return. 396 * 397 * Environments: 398 * 399 * This service can be called from: 400 * 401 * - Kernel module initialization/cleanup code 402 * - User-space task (non-RT) 403 * 404 * Rescheduling: possible. 405 */ 406 void rtdm_task_join_nrt(rtdm_task_t *task, unsigned int poll_delay) 407 { 408 #define JOIN_TIMEOUT 1000 // in millisecs 409 int t; 410 411 412 trace_mark(xn_rtdm, task_joinnrt, "thread %p poll_delay %u", 413 task, poll_delay); 414 415 for (t = 0; task->magic && t < JOIN_TIMEOUT; t += poll_delay) { 416 msleep(poll_delay); 417 } 418 rtdm_task_destroy(task); 419 } 420 421 422 423 424 425 426 427 428 EXPORT_SYMBOL(rtdm_task_join_nrt); 429 430 /** 431 * @brief Busy-wait a specified amount of time 432 * 433 * @param[in] delay Delay in nanoseconds. Note that a zero delay does @b not 434 * have the meaning of @c RTDM_TIMEOUT_INFINITE here. 435 * 436 * @note The caller must not be migratable to different CPUs while executing 437 * this service. Otherwise, the actual delay will be undefined. 438 * 439 * Environments: 440 * 441 * This service can be called from: 442 * 443 * - Kernel module initialization/cleanup code 444 * - Interrupt service routine (should be avoided or kept short) 445 * - Kernel-based task 446 * - User-space task (RT, non-RT) 447 * 448 * Rescheduling: never (except due to external interruptions). 449 */ 450 void rtdm_task_busy_sleep(nanosecs_rel_t delay) 451 { 452 xnticks_t wakeup = rtai_rdtsc() + llimd(delay, tuned.cpu_freq, 1000000000); 453 while ((xnticks_t)(rtai_rdtsc() - wakeup) < 0) 454 cpu_relax(); 455 } 456 457 EXPORT_SYMBOL(rtdm_task_busy_sleep); 458 /** @} */ 459 460 /*! 461 * @ingroup driverapi 462 * @defgroup rtdmtimer Timer Services 463 * @{ 464 */ 465 466 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 467 /** 468 * @brief Initialise a timer 469 * 470 * @param[in,out] timer Timer handle 471 * @param[in] handler Handler to be called on timer expiry 472 * @param[in] name Optional timer name 473 * 474 * @return 0 on success, otherwise negative error code 475 * 476 * Environments: 477 * 478 * This service can be called from: 479 * 480 * - Kernel module initialization/cleanup code 481 * - Kernel-based task 482 * - User-space task (RT, non-RT) 483 * 484 * Rescheduling: never. 485 */ 486 int rtdm_timer_init(rtdm_timer_t *timer, rtdm_timer_handler_t handler, 487 const char *name); 488 #endif /* DOXYGEN_CPP */ 489 490 /** 491 * @brief Destroy a timer 492 * 493 * @param[in,out] timer Timer handle as returned by rtdm_timer_init() 494 * 495 * Environments: 496 * 497 * This service can be called from: 498 * 499 * - Kernel module initialization/cleanup code 500 * - Kernel-based task 501 * - User-space task (RT, non-RT) 502 * 503 * Rescheduling: never. 504 */ 505 void rtdm_timer_destroy(rtdm_timer_t *timer) 506 { 507 508 509 510 xntimer_destroy(timer); 511 512 } 513 514 EXPORT_SYMBOL(rtdm_timer_destroy); 515 516 /** 517 * @brief Start a timer 518 * 519 * @param[in,out] timer Timer handle as returned by rtdm_timer_init() 520 * @param[in] expiry Firing time of the timer, @c mode defines if relative or 521 * absolute 522 * @param[in] interval Relative reload value, > 0 if the timer shall work in 523 * periodic mode with the specific interval, 0 for one-shot timers 524 * @param[in] mode Defines the operation mode, see @ref RTDM_TIMERMODE_xxx for 525 * possible values 526 * 527 * @return 0 on success, otherwise: 528 * 529 * - -ETIMEDOUT is returned if @c expiry describes an absolute date in the 530 * past. 531 * 532 * Environments: 533 * 534 * This service can be called from: 535 * 536 * - Kernel module initialization/cleanup code 537 * - Interrupt service routine 538 * - Kernel-based task 539 * - User-space task (RT, non-RT) 540 * 541 * Rescheduling: never. 542 */ 543 int rtdm_timer_start(rtdm_timer_t *timer, nanosecs_abs_t expiry, 544 nanosecs_rel_t interval, enum rtdm_timer_mode mode) 545 { 546 547 int err; 548 549 550 err = xntimer_start(timer, xntbase_ns2ticks(rtdm_tbase, expiry), 551 xntbase_ns2ticks(rtdm_tbase, interval), 552 (xntmode_t)mode); 553 554 555 return err; 556 } 557 558 EXPORT_SYMBOL(rtdm_timer_start); 559 560 /** 561 * @brief Stop a timer 562 * 563 * @param[in,out] timer Timer handle as returned by rtdm_timer_init() 564 * 565 * Environments: 566 * 567 * This service can be called from: 568 * 569 * - Kernel module initialization/cleanup code 570 * - Interrupt service routine 571 * - Kernel-based task 572 * - User-space task (RT, non-RT) 573 * 574 * Rescheduling: never. 575 */ 576 void rtdm_timer_stop(rtdm_timer_t *timer) 577 { 578 579 580 581 xntimer_stop(timer); 582 583 } 584 585 EXPORT_SYMBOL(rtdm_timer_stop); 586 587 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 588 /** 589 * @brief Start a timer from inside a timer handler 590 * 591 * @param[in,out] timer Timer handle as returned by rtdm_timer_init() 592 * @param[in] expiry Firing time of the timer, @c mode defines if relative or 593 * absolute 594 * @param[in] interval Relative reload value, > 0 if the timer shall work in 595 * periodic mode with the specific interval, 0 for one-shot timers 596 * @param[in] mode Defines the operation mode, see @ref RTDM_TIMERMODE_xxx for 597 * possible values 598 * 599 * @return 0 on success, otherwise: 600 * 601 * - -ETIMEDOUT is returned if @c expiry describes an absolute date in the 602 * past. 603 * 604 * Environments: 605 * 606 * This service can be called from: 607 * 608 * - Timer handler 609 * 610 * Rescheduling: never. 611 */ 612 int rtdm_timer_start_in_handler(rtdm_timer_t *timer, nanosecs_abs_t expiry, 613 nanosecs_rel_t interval, 614 enum rtdm_timer_mode mode); 615 616 /** 617 * @brief Stop a timer from inside a timer handler 618 * 619 * @param[in,out] timer Timer handle as returned by rtdm_timer_init() 620 * 621 * Environments: 622 * 623 * This service can be called from: 624 * 625 * - Timer handler 626 * 627 * Rescheduling: never. 628 */ 629 void rtdm_timer_stop_in_handler(rtdm_timer_t *timer); 630 #endif /* DOXYGEN_CPP */ 631 /** @} */ 632 633 /* --- RTAI proper common to events, sems and mtxes --- */ 634 635 static inline int _sem_wait(void *sem) 636 { 637 if (rt_sem_wait(sem) < RTE_LOWERR) { 638 return 0; 639 } 640 return _rt_whoami()->unblocked ? -EINTR : -EIDRM; 641 } 642 643 static inline int _sem_wait_timed(void *sem, nanosecs_rel_t timeout, rtdm_toseq_t *timeout_seq) 644 { 645 int ret; 646 647 if (timeout < 0) { 648 return (ret = rt_sem_wait_if(sem)) > 0 ? 0 : ret != RTE_OBJINV ? -EWOULDBLOCK : -EIDRM; 649 } 650 if (!timeout) { 651 /* infinite timeout */ 652 ret = rt_sem_wait(sem); 653 } else { 654 /* timeout sequence, i.e. abs timeout, or relative timeout */ 655 ret = timeout_seq ? rt_sem_wait_until(sem, *timeout_seq) : rt_sem_wait_timed(sem, nano2count(timeout)); 656 } 657 if (ret < RTE_LOWERR) { 658 return 0; 659 } 660 if (ret == SEM_TIMOUT) { 661 return -ETIMEDOUT; 662 } 663 return _rt_whoami()->unblocked ? -EINTR : -EIDRM; 664 } 665 666 /*! 667 * @ingroup driverapi 668 * @defgroup rtdmsync Synchronisation Services 669 * @{ 670 */ 671 672 /*! 673 * @name Timeout Sequence Management 674 * @{ 675 */ 676 677 /** 678 * @brief Initialise a timeout sequence 679 * 680 * This service initialises a timeout sequence handle according to the given 681 * timeout value. Timeout sequences allow to maintain a continuous @a timeout 682 * across multiple calls of blocking synchronisation services. A typical 683 * application scenario is given below. 684 * 685 * @param[in,out] timeout_seq Timeout sequence handle 686 * @param[in] timeout Relative timeout in nanoseconds, see 687 * @ref RTDM_TIMEOUT_xxx for special values 688 * 689 * Application Scenario: 690 * @code 691 int device_service_routine(...) 692 { 693 rtdm_toseq_t timeout_seq; 694 ... 695 696 rtdm_toseq_init(&timeout_seq, timeout); 697 ... 698 while (received < requested) { 699 ret = rtdm_event_timedwait(&data_available, timeout, &timeout_seq); 700 if (ret < 0) // including -ETIMEDOUT 701 break; 702 703 // receive some data 704 ... 705 } 706 ... 707 } 708 * @endcode 709 * Using a timeout sequence in such a scenario avoids that the user-provided 710 * relative @c timeout is restarted on every call to rtdm_event_timedwait(), 711 * potentially causing an overall delay that is larger than specified by 712 * @c timeout. Moreover, all functions supporting timeout sequences also 713 * interpret special timeout values (infinite and non-blocking), 714 * disburdening the driver developer from handling them separately. 715 * 716 * RTAI REMARK: 717 * This is just a confusing set of words to patch missing APIs with absolute 718 * deadlines in xenomai. In short a timeout_seq is nothing but the absolute 719 * deadline and so should be used in any related RTAI API that does it so 720 * natively already. Thus the same code in RTAI would simply be: 721 * @code 722 int device_service_routine(...) 723 { 724 ... 725 while (received < requested) { 726 ret = rtdm_event_timedwait(&event->synch_base, rt_get_time()+timeout); 727 if (ret < 0) // including -ETIMEDOUT 728 break; 729 ... 730 // receive some data 731 ... 732 } 733 ... 734 } 735 * @endcode 736 * though it is not so because of an easier porting. Nonetheless the RTAI 737 * implementation takes care of using its simpler native way anyhow. 738 * END OF RTAI REMARK. 739 * 740 * Environments: 741 * 742 * This service can be called from: 743 * 744 * - Kernel-based task 745 * - User-space task (RT) 746 * 747 * Rescheduling: never. 748 */ 749 void rtdm_toseq_init(rtdm_toseq_t *timeout_seq, nanosecs_rel_t timeout) 750 { 751 752 753 754 755 756 *timeout_seq = rt_get_time() + nano2count(timeout); 757 } 758 759 EXPORT_SYMBOL(rtdm_toseq_init); 760 /** @} */ 761 762 /*! 763 * @name Event Services 764 * @{ 765 */ 766 767 /** 768 * @brief Initialise an event 769 * 770 * @param[in,out] event Event handle 771 * @param[in] pending Non-zero if event shall be initialised as set, 0 otherwise 772 * 773 * Environments: 774 * 775 * This service can be called from: 776 * 777 * - Kernel module initialization/cleanup code 778 * - Kernel-based task 779 * - User-space task (RT, non-RT) 780 * 781 * Rescheduling: never. 782 */ 783 void rtdm_event_init(rtdm_event_t *event, unsigned long pending) 784 { 785 spl_t s; 786 787 trace_mark(xn_rtdm, event_init, 788 "event %p pending %lu", event, pending); 789 790 791 792 if (pending) 793 event->pending = pending; 794 rt_typed_sem_init(&event->synch_base, 0, BIN_SEM | PRIO_Q); 795 xnlock_get_irqsave(&nklock, s); 796 xnselect_init(&event->select_block); 797 798 xnlock_put_irqrestore(&nklock, s); 799 } 800 801 EXPORT_SYMBOL(rtdm_event_init); 802 803 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 804 /** 805 * @brief Destroy an event 806 * 807 * @param[in,out] event Event handle as returned by rtdm_event_init() 808 * 809 * Environments: 810 * 811 * This service can be called from: 812 * 813 * - Kernel module initialization/cleanup code 814 * - Kernel-based task 815 * - User-space task (RT, non-RT) 816 * 817 * Rescheduling: possible. 818 */ 819 void rtdm_event_destroy(rtdm_event_t *event); 820 821 /** 822 * @brief Signal an event occurrence to currently listening waiters 823 * 824 * This function wakes up all current waiters of the given event, but it does 825 * not change the event state. Subsequently callers of rtdm_event_wait() or 826 * rtdm_event_timedwait() will therefore be blocked first. 827 * 828 * @param[in,out] event Event handle as returned by rtdm_event_init() 829 * 830 * Environments: 831 * 832 * This service can be called from: 833 * 834 * - Kernel module initialization/cleanup code 835 * - Interrupt service routine 836 * - Kernel-based task 837 * - User-space task (RT, non-RT) 838 * 839 * Rescheduling: possible. 840 */ 841 void rtdm_event_pulse(rtdm_event_t *event); 842 #endif /* DOXYGEN_CPP */ 843 844 /** 845 * @brief Signal an event occurrence 846 * 847 * This function sets the given event and wakes up all current waiters. If no 848 * waiter is presently registered, the next call to rtdm_event_wait() or 849 * rtdm_event_timedwait() will return immediately. 850 * 851 * @param[in,out] event Event handle as returned by rtdm_event_init() 852 * 853 * Environments: 854 * 855 * This service can be called from: 856 * 857 * - Kernel module initialization/cleanup code 858 * - Interrupt service routine 859 * - Kernel-based task 860 * - User-space task (RT, non-RT) 861 * 862 * Rescheduling: possible. 863 */ 864 void rtdm_event_signal(rtdm_event_t *event) 865 { 866 unsigned long flags; 867 868 869 trace_mark(xn_rtdm, event_signal, "event %p", event); 870 871 flags = rt_global_save_flags_and_cli(); 872 __set_bit(0, &event->pending); 873 rt_sem_broadcast(&event->synch_base); 874 rt_global_restore_flags(flags); 875 SELECT_SIGNAL(&event->select_block, 1); 876 } 877 878 879 880 881 882 883 884 EXPORT_SYMBOL(rtdm_event_signal); 885 886 /** 887 * @brief Wait on event occurrence 888 * 889 * This is the light-weight version of rtdm_event_timedwait(), implying an 890 * infinite timeout. 891 * 892 * @param[in,out] event Event handle as returned by rtdm_event_init() 893 * 894 * @return 0 on success, otherwise: 895 * 896 * - -EINTR is returned if calling task has been unblock by a signal or 897 * explicitly via rtdm_task_unblock(). 898 * 899 * - -EIDRM is returned if @a event has been destroyed. 900 * 901 * - -EPERM @e may be returned if an illegal invocation environment is 902 * detected. 903 * 904 * Environments: 905 * 906 * This service can be called from: 907 * 908 * - Kernel-based task 909 * - User-space task (RT) 910 * 911 * Rescheduling: possible. 912 */ 913 int rtdm_event_wait(rtdm_event_t *event) 914 { 915 unsigned long flags; 916 int ret; 917 918 flags = rt_global_save_flags_and_cli(); 919 if (!__test_and_clear_bit(0, &event->pending)) { 920 if (!(ret = _sem_wait(&event->synch_base))) { 921 __clear_bit(0, &event->pending); 922 } 923 } else { 924 ret = 0; 925 } 926 rt_global_restore_flags(flags); 927 928 return ret; 929 } 930 931 EXPORT_SYMBOL(rtdm_event_wait); 932 933 /** 934 * @brief Wait on event occurrence with timeout 935 * 936 * This function waits or tests for the occurence of the given event, taking 937 * the provided timeout into account. On successful return, the event is 938 * reset. 939 * 940 * @param[in,out] event Event handle as returned by rtdm_event_init() 941 * @param[in] timeout Relative timeout in nanoseconds, see 942 * @ref RTDM_TIMEOUT_xxx for special values 943 * @param[in,out] timeout_seq Handle of a timeout sequence as returned by 944 * rtdm_toseq_init() or NULL 945 * 946 * @return 0 on success, otherwise: 947 * 948 * - -ETIMEDOUT is returned if the if the request has not been satisfied 949 * within the specified amount of time. 950 * 951 * - -EINTR is returned if calling task has been unblock by a signal or 952 * explicitly via rtdm_task_unblock(). 953 * 954 * - -EIDRM is returned if @a event has been destroyed. 955 * 956 * - -EPERM @e may be returned if an illegal invocation environment is 957 * detected. 958 * 959 * - -EWOULDBLOCK is returned if a negative @a timeout (i.e., non-blocking 960 * operation) has been specified. 961 * 962 * Environments: 963 * 964 * This service can be called from: 965 * 966 * - Kernel-based task 967 * - User-space task (RT) 968 * 969 * Rescheduling: possible. 970 */ 971 int rtdm_event_timedwait(rtdm_event_t *event, nanosecs_rel_t timeout, 972 rtdm_toseq_t *timeout_seq) 973 { 974 unsigned long flags; 975 int ret; 976 977 978 979 980 trace_mark(xn_rtdm, event_timedwait, 981 "event %p timeout %Lu timeout_seq %p timeout_seq_value %Lu", 982 event, (long long)timeout, timeout_seq, (long long)(timeout_seq ? *timeout_seq : 0)); 983 984 flags = rt_global_save_flags_and_cli(); 985 if (!__test_and_clear_bit(0, &event->pending)) { 986 if (!(ret = _sem_wait_timed(&event->synch_base, timeout, timeout_seq))) { 987 __clear_bit(0, &event->pending); 988 rt_global_restore_flags(flags); 989 SELECT_SIGNAL(&event->select_block, 0); 990 } else { 991 rt_global_restore_flags(flags); 992 } 993 } else { 994 rt_global_restore_flags(flags); 995 SELECT_SIGNAL(&event->select_block, 0); 996 ret = 0; 997 } 998 999 return ret; 1000 } 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 EXPORT_SYMBOL(rtdm_event_timedwait); 1033 1034 /** 1035 * @brief Clear event state 1036 * 1037 * @param[in,out] event Event handle as returned by rtdm_event_init() 1038 * 1039 * Environments: 1040 * 1041 * This service can be called from: 1042 * 1043 * - Kernel module initialization/cleanup code 1044 * - Interrupt service routine 1045 * - Kernel-based task 1046 * - User-space task (RT, non-RT) 1047 * 1048 * Rescheduling: never. 1049 */ 1050 void rtdm_event_clear(rtdm_event_t *event) 1051 { 1052 1053 1054 trace_mark(xn_rtdm, event_clear, "event %p", event); 1055 1056 1057 event->pending = 0; 1058 SELECT_SIGNAL(&event->select_block, 0); 1059 } 1060 1061 1062 1063 1064 EXPORT_SYMBOL(rtdm_event_clear); 1065 1066 #ifdef CONFIG_RTAI_RTDM_SELECT 1067 /** 1068 * @brief Bind a selector to an event 1069 * 1070 * This functions binds the given selector to an event so that the former is 1071 * notified when the event state changes. Typically the select binding handler 1072 * will invoke this service. 1073 * 1074 * @param[in,out] event Event handle as returned by rtdm_event_init() 1075 * @param[in,out] selector Selector as passed to the select binding handler 1076 * @param[in] type Type of the bound event as passed to the select binding handler 1077 * @param[in] fd_index File descriptor index as passed to the select binding 1078 * handler 1079 * 1080 * @return 0 on success, otherwise: 1081 * 1082 * - -ENOMEM is returned if there is insufficient memory to establish the 1083 * dynamic binding. 1084 * 1085 * - -EINVAL is returned if @a type or @a fd_index are invalid. 1086 * 1087 * Environments: 1088 * 1089 * This service can be called from: 1090 * 1091 * - Kernel module initialization/cleanup code 1092 * - Kernel-based task 1093 * - User-space task (RT, non-RT) 1094 * 1095 * Rescheduling: never. 1096 */ 1097 int rtdm_event_select_bind(rtdm_event_t *event, rtdm_selector_t *selector, 1098 enum rtdm_selecttype type, unsigned fd_index) 1099 { 1100 struct xnselect_binding *binding; 1101 int err; 1102 spl_t s; 1103 1104 binding = xnmalloc(sizeof(*binding)); 1105 if (!binding) 1106 return -ENOMEM; 1107 1108 xnlock_get_irqsave(&nklock, s); 1109 err = xnselect_bind(&event->select_block, 1110 binding, selector, type, fd_index, 1111 event->pending || 1112 event->synch_base.magic != RT_SEM_MAGIC); 1113 1114 xnlock_put_irqrestore(&nklock, s); 1115 1116 if (err) 1117 xnfree(binding); 1118 1119 return err; 1120 } 1121 EXPORT_SYMBOL(rtdm_event_select_bind); 1122 #endif /* CONFIG_RTAI_RTDM_SELECT */ 1123 /** @} */ 1124 1125 /*! 1126 * @name Semaphore Services 1127 * @{ 1128 */ 1129 1130 /** 1131 * @brief Initialise a semaphore 1132 * 1133 * @param[in,out] sem Semaphore handle 1134 * @param[in] value Initial value of the semaphore 1135 * 1136 * Environments: 1137 * 1138 * This service can be called from: 1139 * 1140 * - Kernel module initialization/cleanup code 1141 * - Kernel-based task 1142 * - User-space task (RT, non-RT) 1143 * 1144 * Rescheduling: never. 1145 */ 1146 void rtdm_sem_init(rtdm_sem_t *sem, unsigned long value) 1147 { 1148 spl_t s; 1149 1150 trace_mark(xn_rtdm, sem_init, "sem %p value %lu", sem, value); 1151 1152 1153 1154 1155 rt_typed_sem_init(&sem->sem, value, CNT_SEM | PRIO_Q); 1156 1157 xnlock_get_irqsave(&nklock, s); 1158 xnselect_init(&sem->select_block); 1159 xnlock_put_irqrestore(&nklock, s); 1160 } 1161 1162 EXPORT_SYMBOL(rtdm_sem_init); 1163 1164 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 1165 /** 1166 * @brief Destroy a semaphore 1167 * 1168 * @param[in,out] sem Semaphore handle as returned by rtdm_sem_init() 1169 * 1170 * Environments: 1171 * 1172 * This service can be called from: 1173 * 1174 * - Kernel module initialization/cleanup code 1175 * - Kernel-based task 1176 * - User-space task (RT, non-RT) 1177 * 1178 * Rescheduling: possible. 1179 */ 1180 void rtdm_sem_destroy(rtdm_sem_t *sem); 1181 #endif /* DOXYGEN_CPP */ 1182 1183 /** 1184 * @brief Decrement a semaphore 1185 * 1186 * This is the light-weight version of rtdm_sem_timeddown(), implying an 1187 * infinite timeout. 1188 * 1189 * @param[in,out] sem Semaphore handle as returned by rtdm_sem_init() 1190 * 1191 * @return 0 on success, otherwise: 1192 * 1193 * - -EINTR is returned if calling task has been unblock by a signal or 1194 * explicitly via rtdm_task_unblock(). 1195 * 1196 * - -EIDRM is returned if @a sem has been destroyed. 1197 * 1198 * - -EPERM @e may be returned if an illegal invocation environment is 1199 * detected. 1200 * 1201 * Environments: 1202 * 1203 * This service can be called from: 1204 * 1205 * - Kernel-based task 1206 * - User-space task (RT) 1207 * 1208 * Rescheduling: possible. 1209 */ 1210 int rtdm_sem_down(rtdm_sem_t *sem) 1211 { 1212 return _sem_wait(&sem->sem); 1213 } 1214 1215 EXPORT_SYMBOL(rtdm_sem_down); 1216 1217 /** 1218 * @brief Decrement a semaphore with timeout 1219 * 1220 * This function tries to decrement the given semphore's value if it is 1221 * positive on entry. If not, the caller is blocked unless non-blocking 1222 * operation was selected. 1223 * 1224 * @param[in,out] sem Semaphore handle as returned by rtdm_sem_init() 1225 * @param[in] timeout Relative timeout in nanoseconds, see 1226 * @ref RTDM_TIMEOUT_xxx for special values 1227 * @param[in,out] timeout_seq Handle of a timeout sequence as returned by 1228 * rtdm_toseq_init() or NULL 1229 * 1230 * @return 0 on success, otherwise: 1231 * 1232 * - -ETIMEDOUT is returned if the if the request has not been satisfied 1233 * within the specified amount of time. 1234 * 1235 * - -EWOULDBLOCK is returned if @a timeout is negative and the semaphore 1236 * value is currently not positive. 1237 * 1238 * - -EINTR is returned if calling task has been unblock by a signal or 1239 * explicitly via rtdm_task_unblock(). 1240 * 1241 * - -EIDRM is returned if @a sem has been destroyed. 1242 * 1243 * - -EPERM @e may be returned if an illegal invocation environment is 1244 * detected. 1245 * 1246 * Environments: 1247 * 1248 * This service can be called from: 1249 * 1250 * - Kernel-based task 1251 * - User-space task (RT) 1252 * 1253 * Rescheduling: possible. 1254 */ 1255 int rtdm_sem_timeddown(rtdm_sem_t *sem, nanosecs_rel_t timeout, 1256 rtdm_toseq_t *timeout_seq) 1257 { 1258 1259 int retval; 1260 1261 1262 1263 1264 trace_mark(xn_rtdm, sem_timedwait, 1265 "sem %p timeout %Lu timeout_seq %p timeout_seq_value %Lu", 1266 sem, (long long)timeout, timeout_seq, (long long)(timeout_seq ? *timeout_seq : 0)); 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 if ((retval = _sem_wait_timed(&sem->sem, timeout, timeout_seq)) == 1) { 1302 SELECT_SIGNAL(&sem->select_block, 0); 1303 } 1304 return retval; 1305 } 1306 1307 EXPORT_SYMBOL(rtdm_sem_timeddown); 1308 1309 /** 1310 * @brief Increment a semaphore 1311 * 1312 * This function increments the given semphore's value, waking up a potential 1313 * waiter which was blocked upon rtdm_sem_down(). 1314 * 1315 * @param[in,out] sem Semaphore handle as returned by rtdm_sem_init() 1316 * 1317 * Environments: 1318 * 1319 * This service can be called from: 1320 * 1321 * - Kernel module initialization/cleanup code 1322 * - Interrupt service routine 1323 * - Kernel-based task 1324 * - User-space task (RT, non-RT) 1325 * 1326 * Rescheduling: possible. 1327 */ 1328 void rtdm_sem_up(rtdm_sem_t *sem) 1329 { 1330 1331 1332 trace_mark(xn_rtdm, sem_up, "sem %p", sem); 1333 1334 1335 rt_sem_signal(&sem->sem); 1336 if (sem->sem.count > 0) { 1337 SELECT_SIGNAL(&sem->select_block, 1); 1338 } 1339 } 1340 1341 1342 1343 1344 1345 1346 EXPORT_SYMBOL(rtdm_sem_up); 1347 1348 #ifdef CONFIG_RTAI_RTDM_SELECT 1349 /** 1350 * @brief Bind a selector to a semaphore 1351 * 1352 * This functions binds the given selector to the semaphore so that the former 1353 * is notified when the semaphore state changes. Typically the select binding 1354 * handler will invoke this service. 1355 * 1356 * @param[in,out] sem Semaphore handle as returned by rtdm_sem_init() 1357 * @param[in,out] selector Selector as passed to the select binding handler 1358 * @param[in] type Type of the bound event as passed to the select binding handler 1359 * @param[in] fd_index File descriptor index as passed to the select binding 1360 * handler 1361 * 1362 * @return 0 on success, otherwise: 1363 * 1364 * - -ENOMEM is returned if there is insufficient memory to establish the 1365 * dynamic binding. 1366 * 1367 * - -EINVAL is returned if @a type or @a fd_index are invalid. 1368 * 1369 * Environments: 1370 * 1371 * This service can be called from: 1372 * 1373 * - Kernel module initialization/cleanup code 1374 * - Kernel-based task 1375 * - User-space task (RT, non-RT) 1376 * 1377 * Rescheduling: never. 1378 */ 1379 int rtdm_sem_select_bind(rtdm_sem_t *sem, rtdm_selector_t *selector, 1380 enum rtdm_selecttype type, unsigned fd_index) 1381 { 1382 struct xnselect_binding *binding; 1383 int err; 1384 spl_t s; 1385 1386 binding = xnmalloc(sizeof(*binding)); 1387 if (!binding) 1388 return -ENOMEM; 1389 1390 xnlock_get_irqsave(&nklock, s); 1391 err = xnselect_bind(&sem->select_block, binding, selector, 1392 type, fd_index, 1393 sem->sem.count > 0 || 1394 sem->sem.magic != RT_SEM_MAGIC); 1395 1396 xnlock_put_irqrestore(&nklock, s); 1397 1398 if (err) 1399 xnfree(binding); 1400 1401 return err; 1402 } 1403 EXPORT_SYMBOL(rtdm_sem_select_bind); 1404 #endif /* CONFIG_RTAI_RTDM_SELECT */ 1405 /** @} */ 1406 1407 /*! 1408 * @name Mutex Services 1409 * @{ 1410 */ 1411 1412 /** 1413 * @brief Initialise a mutex 1414 * 1415 * This function initalises a basic mutex with priority inversion protection. 1416 * "Basic", as it does not allow a mutex owner to recursively lock the same 1417 * mutex again. 1418 * 1419 * @param[in,out] mutex Mutex handle 1420 * 1421 * Environments: 1422 * 1423 * This service can be called from: 1424 * 1425 * - Kernel module initialization/cleanup code 1426 * - Kernel-based task 1427 * - User-space task (RT, non-RT) 1428 * 1429 * Rescheduling: never. 1430 */ 1431 void rtdm_mutex_init(rtdm_mutex_t *mutex) 1432 { 1433 1434 1435 1436 1437 1438 1439 1440 1441 rt_typed_sem_init(mutex, 1, RES_SEM | PRIO_Q); 1442 } 1443 1444 EXPORT_SYMBOL(rtdm_mutex_init); 1445 1446 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 1447 /** 1448 * @brief Destroy a mutex 1449 * 1450 * @param[in,out] mutex Mutex handle as returned by rtdm_mutex_init() 1451 * 1452 * Environments: 1453 * 1454 * This service can be called from: 1455 * 1456 * - Kernel module initialization/cleanup code 1457 * - Kernel-based task 1458 * - User-space task (RT, non-RT) 1459 * 1460 * Rescheduling: possible. 1461 */ 1462 void rtdm_mutex_destroy(rtdm_mutex_t *mutex); 1463 1464 /** 1465 * @brief Release a mutex 1466 * 1467 * This function releases the given mutex, waking up a potential waiter which 1468 * was blocked upon rtdm_mutex_lock() or rtdm_mutex_timedlock(). 1469 * 1470 * @param[in,out] mutex Mutex handle as returned by rtdm_mutex_init() 1471 * 1472 * Environments: 1473 * 1474 * This service can be called from: 1475 * 1476 * - Kernel-based task 1477 * - User-space task (RT) 1478 * 1479 * Rescheduling: possible. 1480 */ 1481 void rtdm_mutex_unlock(rtdm_mutex_t *mutex); 1482 #endif /* DOXYGEN_CPP */ 1483 1484 /** 1485 * @brief Request a mutex 1486 * 1487 * This is the light-weight version of rtdm_mutex_timedlock(), implying an 1488 * infinite timeout. 1489 * 1490 * @param[in,out] mutex Mutex handle as returned by rtdm_mutex_init() 1491 * 1492 * @return 0 on success, otherwise: 1493 * 1494 * - -EIDRM is returned if @a mutex has been destroyed. 1495 * 1496 * - -EPERM @e may be returned if an illegal invocation environment is 1497 * detected. 1498 * 1499 * Environments: 1500 * 1501 * This service can be called from: 1502 * 1503 * - Kernel-based task 1504 * - User-space task (RT) 1505 * 1506 * Rescheduling: possible. 1507 */ 1508 int rtdm_mutex_lock(rtdm_mutex_t *mutex) 1509 { 1510 int ret; while ((ret = _sem_wait(mutex)) == -EINTR); return ret; 1511 } 1512 1513 EXPORT_SYMBOL(rtdm_mutex_lock); 1514 1515 /** 1516 * @brief Request a mutex with timeout 1517 * 1518 * This function tries to acquire the given mutex. If it is not available, the 1519 * caller is blocked unless non-blocking operation was selected. 1520 * 1521 * @param[in,out] mutex Mutex handle as returned by rtdm_mutex_init() 1522 * @param[in] timeout Relative timeout in nanoseconds, see 1523 * @ref RTDM_TIMEOUT_xxx for special values 1524 * @param[in,out] timeout_seq Handle of a timeout sequence as returned by 1525 * rtdm_toseq_init() or NULL 1526 * 1527 * @return 0 on success, otherwise: 1528 * 1529 * - -ETIMEDOUT is returned if the if the request has not been satisfied 1530 * within the specified amount of time. 1531 * 1532 * - -EWOULDBLOCK is returned if @a timeout is negative and the semaphore 1533 * value is currently not positive. 1534 * 1535 * - -EIDRM is returned if @a mutex has been destroyed. 1536 * 1537 * - -EPERM @e may be returned if an illegal invocation environment is 1538 * detected. 1539 * 1540 * Environments: 1541 * 1542 * This service can be called from: 1543 * 1544 * - Kernel-based task 1545 * - User-space task (RT) 1546 * 1547 * Rescheduling: possible. 1548 */ 1549 int rtdm_mutex_timedlock(rtdm_mutex_t *mutex, nanosecs_rel_t timeout, 1550 rtdm_toseq_t *timeout_seq) 1551 { 1552 int retval; 1553 1554 1555 1556 trace_mark(xn_rtdm, mutex_timedlock, 1557 "mutex %p timeout %Lu timeout_seq %p timeout_seq_value %Lu", 1558 mutex, (long long)timeout, timeout_seq, (long long)(timeout_seq ? *timeout_seq : 0)); 1559 1560 if (timeout_seq) { 1561 while((retval = _sem_wait_timed(mutex, timeout, timeout_seq)) == -EINTR); 1562 } else { 1563 rtdm_toseq_t until = rt_get_time() + nano2count(timeout); 1564 while((retval = _sem_wait_timed(mutex, timeout, &until)) == -EINTR); 1565 } 1566 return retval; 1567 } 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 EXPORT_SYMBOL(rtdm_mutex_timedlock); 1609 /** @} */ 1610 1611 /** @} Synchronisation services */ 1612 1613 /*! 1614 * @ingroup driverapi 1615 * @defgroup rtdmirq Interrupt Management Services 1616 * @{ 1617 */ 1618 1619 /** 1620 * @brief Register an interrupt handler 1621 * 1622 * This function registers the provided handler with an IRQ line and enables 1623 * the line. 1624 * 1625 * @param[in,out] irq_handle IRQ handle 1626 * @param[in] irq_no Line number of the addressed IRQ 1627 * @param[in] handler Interrupt handler 1628 * @param[in] flags Registration flags, see @ref RTDM_IRQTYPE_xxx for details 1629 * @param[in] device_name Device name to show up in real-time IRQ lists 1630 * @param[in] arg Pointer to be passed to the interrupt handler on invocation 1631 * 1632 * @return 0 on success, otherwise: 1633 * 1634 * - -EINVAL is returned if an invalid parameter was passed. 1635 * 1636 * - -EBUSY is returned if the specified IRQ line is already in use. 1637 * 1638 * Environments: 1639 * 1640 * This service can be called from: 1641 * 1642 * - Kernel module initialization/cleanup code 1643 * - Kernel-based task 1644 * - User-space task (RT, non-RT) 1645 * 1646 * Rescheduling: never. 1647 */ 1648 int rtdm_irq_request(rtdm_irq_t *irq_handle, unsigned int irq_no, 1649 rtdm_irq_handler_t handler, unsigned long flags, 1650 const char *device_name, void *arg) 1651 { 1652 int err; 1653 1654 xnintr_init(irq_handle, device_name, irq_no, handler, NULL, flags); 1655 1656 err = xnintr_attach(irq_handle, arg); 1657 if (err) 1658 return err; 1659 1660 err = xnintr_enable(irq_handle); 1661 if (err) 1662 xnintr_detach(irq_handle); 1663 1664 return err; 1665 } 1666 1667 EXPORT_SYMBOL(rtdm_irq_request); 1668 1669 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 1670 /** 1671 * @brief Release an interrupt handler 1672 * 1673 * @param[in,out] irq_handle IRQ handle as returned by rtdm_irq_request() 1674 * 1675 * @return 0 on success, otherwise negative error code 1676 * 1677 * Environments: 1678 * 1679 * This service can be called from: 1680 * 1681 * - Kernel module initialization/cleanup code 1682 * - Kernel-based task 1683 * - User-space task (RT, non-RT) 1684 * 1685 * Rescheduling: never. 1686 */ 1687 int rtdm_irq_free(rtdm_irq_t *irq_handle); 1688 1689 /** 1690 * @brief Enable interrupt line 1691 * 1692 * @param[in,out] irq_handle IRQ handle as returned by rtdm_irq_request() 1693 * 1694 * @return 0 on success, otherwise negative error code 1695 * 1696 * Environments: 1697 * 1698 * This service can be called from: 1699 * 1700 * - Kernel module initialization/cleanup code 1701 * - Interrupt service routine 1702 * - Kernel-based task 1703 * - User-space task (RT, non-RT) 1704 * 1705 * Rescheduling: possible. 1706 */ 1707 int rtdm_irq_enable(rtdm_irq_t *irq_handle); 1708 1709 /** 1710 * @brief Disable interrupt line 1711 * 1712 * @param[in,out] irq_handle IRQ handle as returned by rtdm_irq_request() 1713 * 1714 * @return 0 on success, otherwise negative error code 1715 * 1716 * Environments: 1717 * 1718 * This service can be called from: 1719 * 1720 * - Kernel module initialization/cleanup code 1721 * - Interrupt service routine 1722 * - Kernel-based task 1723 * - User-space task (RT, non-RT) 1724 * 1725 * Rescheduling: never. 1726 */ 1727 int rtdm_irq_disable(rtdm_irq_t *irq_handle); 1728 #endif /* DOXYGEN_CPP */ 1729 1730 /** @} Interrupt Management Services */ 1731 1732 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 1733 1734 /*! 1735 * @ingroup driverapi 1736 * @defgroup nrtsignal Non-Real-Time Signalling Services 1737 * 1738 * These services provide a mechanism to request the execution of a specified 1739 * handler in non-real-time context. The triggering can safely be performed in 1740 * real-time context without suffering from unknown delays. The handler 1741 * execution will be deferred until the next time the real-time subsystem 1742 * releases the CPU to the non-real-time part. 1743 * @{ 1744 */ 1745 1746 /** 1747 * @brief Register a non-real-time signal handler 1748 * 1749 * @param[in,out] nrt_sig Signal handle 1750 * @param[in] handler Non-real-time signal handler 1751 * @param[in] arg Custom argument passed to @c handler() on each invocation 1752 * 1753 * @return 0 on success, otherwise: 1754 * 1755 * - -EAGAIN is returned if no free signal slot is available. 1756 * 1757 * Environments: 1758 * 1759 * This service can be called from: 1760 * 1761 * - Kernel module initialization/cleanup code 1762 * - Kernel-based task 1763 * - User-space task (RT, non-RT) 1764 * 1765 * Rescheduling: never. 1766 */ 1767 int rtdm_nrtsig_init(rtdm_nrtsig_t *nrt_sig, rtdm_nrtsig_handler_t handler, 1768 void *arg); 1769 1770 /** 1771 * @brief Release a non-realtime signal handler 1772 * 1773 * @param[in,out] nrt_sig Signal handle 1774 * 1775 * Environments: 1776 * 1777 * This service can be called from: 1778 * 1779 * - Kernel module initialization/cleanup code 1780 * - Kernel-based task 1781 * - User-space task (RT, non-RT) 1782 * 1783 * Rescheduling: never. 1784 */ 1785 void rtdm_nrtsig_destroy(rtdm_nrtsig_t *nrt_sig); 1786 1787 /** 1788 * Trigger non-real-time signal 1789 * 1790 * @param[in,out] nrt_sig Signal handle 1791 * 1792 * Environments: 1793 * 1794 * This service can be called from: 1795 * 1796 * - Kernel module initialization/cleanup code 1797 * - Interrupt service routine 1798 * - Kernel-based task 1799 * - User-space task (RT, non-RT) 1800 * 1801 * Rescheduling: never in real-time context, possible in non-real-time 1802 * environments. 1803 */ 1804 void rtdm_nrtsig_pend(rtdm_nrtsig_t *nrt_sig); 1805 /** @} Non-Real-Time Signalling Services */ 1806 1807 #endif /* DOXYGEN_CPP */ 1808 1809 /*! 1810 * @ingroup driverapi 1811 * @defgroup util Utility Services 1812 * @{ 1813 */ 1814 1815 1816 struct rtdm_mmap_data { 1817 void *src_vaddr; 1818 phys_addr_t src_paddr; 1819 struct vm_operations_struct *vm_ops; 1820 void *vm_private_data; 1821 }; 1822 1823 static int rtdm_mmap_buffer(struct file *filp, struct vm_area_struct *vma) 1824 { 1825 struct rtdm_mmap_data *mmap_data = filp->private_data; 1826 unsigned long vaddr, maddr, size; 1827 phys_addr_t paddr; 1828 int ret; 1829 1830 vma->vm_ops = mmap_data->vm_ops; 1831 vma->vm_private_data = mmap_data->vm_private_data; 1832 1833 vaddr = (unsigned long)mmap_data->src_vaddr; 1834 paddr = mmap_data->src_paddr; 1835 if (!paddr) 1836 /* kmalloc memory */ 1837 paddr = virt_to_phys((void *)vaddr); 1838 1839 maddr = vma->vm_start; 1840 size = vma->vm_end - vma->vm_start; 1841 1842 #ifdef CONFIG_MMU 1843 /* Catch vmalloc memory (vaddr is 0 for I/O mapping) */ 1844 if ((vaddr >= VMALLOC_START) && (vaddr < VMALLOC_END)) { 1845 unsigned long mapped_size = 0; 1846 1847 RTAI_ASSERT(RTDM, vaddr == PAGE_ALIGN(vaddr), return -EINVAL); 1848 RTAI_ASSERT(RTDM, (size % PAGE_SIZE) == 0, return -EINVAL); 1849 1850 while (mapped_size < size) { 1851 if (xnarch_remap_vm_page(vma, maddr, vaddr)) 1852 return -EAGAIN; 1853 1854 maddr += PAGE_SIZE; 1855 vaddr += PAGE_SIZE; 1856 mapped_size += PAGE_SIZE; 1857 } 1858 xnarch_fault_range(vma); 1859 ret = 0; 1860 } else 1861 #endif /* CONFIG_MMU */ 1862 if (mmap_data->src_paddr) 1863 ret = xnarch_remap_io_page_range(filp, vma, maddr, paddr, 1864 size, PAGE_SHARED); 1865 else { 1866 ret = xnarch_remap_kmem_page_range(vma, maddr, paddr, 1867 size, PAGE_SHARED); 1868 if (!ret) 1869 xnarch_fault_range(vma); 1870 } 1871 1872 return ret; 1873 } 1874 1875 static struct file_operations rtdm_mmap_fops = { 1876 .mmap = rtdm_mmap_buffer, 1877 }; 1878 1879 static int rtdm_do_mmap(rtdm_user_info_t *user_info, 1880 struct rtdm_mmap_data *mmap_data, 1881 size_t len, int prot, void **pptr) 1882 { 1883 struct file *filp; 1884 const struct file_operations *old_fops; 1885 void *old_priv_data; 1886 void *user_ptr; 1887 1888 RTAI_ASSERT(RTDM, xnpod_root_p(), return -EPERM;); 1889 1890 filp = filp_open("/dev/zero", O_RDWR, 0); 1891 if (IS_ERR(filp)) 1892 return PTR_ERR(filp); 1893 1894 old_fops = filp->f_op; 1895 filp->f_op = &rtdm_mmap_fops; 1896 1897 old_priv_data = filp->private_data; 1898 filp->private_data = mmap_data; 1899 1900 down_write(&user_info->mm->mmap_sem); 1901 // user_ptr = (void *)do_mmap(filp, (unsigned long)*pptr, len, prot, 1902 // MAP_SHARED, 0); 1903 user_ptr = (void *)vm_mmap(filp, (unsigned long)*pptr, len, prot, 1904 MAP_SHARED, 0); 1905 up_write(&user_info->mm->mmap_sem); 1906 1907 filp->f_op = (typeof(filp->f_op))old_fops; 1908 filp->private_data = old_priv_data; 1909 1910 filp_close(filp, user_info->files); 1911 1912 if (IS_ERR(user_ptr)) 1913 return PTR_ERR(user_ptr); 1914 1915 *pptr = user_ptr; 1916 return 0; 1917 } 1918 1919 /** 1920 * Map a kernel memory range into the address space of the user. 1921 * 1922 * @param[in] user_info User information pointer as passed to the invoked 1923 * device operation handler 1924 * @param[in] src_addr Kernel virtual address to be mapped 1925 * @param[in] len Length of the memory range 1926 * @param[in] prot Protection flags for the user's memory range, typically 1927 * either PROT_READ or PROT_READ|PROT_WRITE 1928 * @param[in,out] pptr Address of a pointer containing the desired user 1929 * address or NULL on entry and the finally assigned address on return 1930 * @param[in] vm_ops vm_operations to be executed on the vma_area of the 1931 * user memory range or NULL 1932 * @param[in] vm_private_data Private data to be stored in the vma_area, 1933 * primarily useful for vm_operation handlers 1934 * 1935 * @return 0 on success, otherwise (most common values): 1936 * 1937 * - -EINVAL is returned if an invalid start address, size, or destination 1938 * address was passed. 1939 * 1940 * - -ENOMEM is returned if there is insufficient free memory or the limit of 1941 * memory mapping for the user process was reached. 1942 * 1943 * - -EAGAIN is returned if too much memory has been already locked by the 1944 * user process. 1945 * 1946 * - -EPERM @e may be returned if an illegal invocation environment is 1947 * detected. 1948 * 1949 * @note This service only works on memory regions allocated via kmalloc() or 1950 * vmalloc(). To map physical I/O memory to user-space use 1951 * rtdm_iomap_to_user() instead. 1952 * 1953 * @note RTDM supports two models for unmapping the user memory range again. 1954 * One is explicit unmapping via rtdm_munmap(), either performed when the 1955 * user requests it via an IOCTL etc. or when the related device is closed. 1956 * The other is automatic unmapping, triggered by the user invoking standard 1957 * munmap() or by the termination of the related process. To track release of 1958 * the mapping and therefore relinquishment of the referenced physical memory, 1959 * the caller of rtdm_mmap_to_user() can pass a vm_operations_struct on 1960 * invocation, defining a close handler for the vm_area. See Linux 1961 * documentaion (e.g. Linux Device Drivers book) on virtual memory management 1962 * for details. 1963 * 1964 * Environments: 1965 * 1966 * This service can be called from: 1967 * 1968 * - Kernel module initialization/cleanup code 1969 * - User-space task (non-RT) 1970 * 1971 * Rescheduling: possible. 1972 */ 1973 int rtdm_mmap_to_user(rtdm_user_info_t *user_info, 1974 void *src_addr, size_t len, 1975 int prot, void **pptr, 1976 struct vm_operations_struct *vm_ops, 1977 void *vm_private_data) 1978 { 1979 struct rtdm_mmap_data mmap_data = 1980 { src_addr, 0, vm_ops, vm_private_data }; 1981 1982 return rtdm_do_mmap(user_info, &mmap_data, len, prot, pptr); 1983 } 1984 1985 EXPORT_SYMBOL(rtdm_mmap_to_user); 1986 1987 /** 1988 * Map an I/O memory range into the address space of the user. 1989 * 1990 * @param[in] user_info User information pointer as passed to the invoked 1991 * device operation handler 1992 * @param[in] src_addr physical I/O address to be mapped 1993 * @param[in] len Length of the memory range 1994 * @param[in] prot Protection flags for the user's memory range, typically 1995 * either PROT_READ or PROT_READ|PROT_WRITE 1996 * @param[in,out] pptr Address of a pointer containing the desired user 1997 * address or NULL on entry and the finally assigned address on return 1998 * @param[in] vm_ops vm_operations to be executed on the vma_area of the 1999 * user memory range or NULL 2000 * @param[in] vm_private_data Private data to be stored in the vma_area, 2001 * primarily useful for vm_operation handlers 2002 * 2003 * @return 0 on success, otherwise (most common values): 2004 * 2005 * - -EINVAL is returned if an invalid start address, size, or destination 2006 * address was passed. 2007 * 2008 * - -ENOMEM is returned if there is insufficient free memory or the limit of 2009 * memory mapping for the user process was reached. 2010 * 2011 * - -EAGAIN is returned if too much memory has been already locked by the 2012 * user process. 2013 * 2014 * - -EPERM @e may be returned if an illegal invocation environment is 2015 * detected. 2016 * 2017 * @note RTDM supports two models for unmapping the user memory range again. 2018 * One is explicit unmapping via rtdm_munmap(), either performed when the 2019 * user requests it via an IOCTL etc. or when the related device is closed. 2020 * The other is automatic unmapping, triggered by the user invoking standard 2021 * munmap() or by the termination of the related process. To track release of 2022 * the mapping and therefore relinquishment of the referenced physical memory, 2023 * the caller of rtdm_iomap_to_user() can pass a vm_operations_struct on 2024 * invocation, defining a close handler for the vm_area. See Linux 2025 * documentaion (e.g. Linux Device Drivers book) on virtual memory management 2026 * for details. 2027 * 2028 * Environments: 2029 * 2030 * This service can be called from: 2031 * 2032 * - Kernel module initialization/cleanup code 2033 * - User-space task (non-RT) 2034 * 2035 * Rescheduling: possible. 2036 */ 2037 int rtdm_iomap_to_user(rtdm_user_info_t *user_info, 2038 phys_addr_t src_addr, size_t len, 2039 int prot, void **pptr, 2040 struct vm_operations_struct *vm_ops, 2041 void *vm_private_data) 2042 { 2043 struct rtdm_mmap_data mmap_data = 2044 { NULL, src_addr, vm_ops, vm_private_data }; 2045 2046 return rtdm_do_mmap(user_info, &mmap_data, len, prot, pptr); 2047 } 2048 2049 EXPORT_SYMBOL(rtdm_iomap_to_user); 2050 2051 /** 2052 * Unmap a user memory range. 2053 * 2054 * @param[in] user_info User information pointer as passed to 2055 * rtdm_mmap_to_user() when requesting to map the memory range 2056 * @param[in] ptr User address or the memory range 2057 * @param[in] len Length of the memory range 2058 * 2059 * @return 0 on success, otherwise: 2060 * 2061 * - -EINVAL is returned if an invalid address or size was passed. 2062 * 2063 * - -EPERM @e may be returned if an illegal invocation environment is 2064 * detected. 2065 * 2066 * Environments: 2067 * 2068 * This service can be called from: 2069 * 2070 * - Kernel module initialization/cleanup code 2071 * - User-space task (non-RT) 2072 * 2073 * Rescheduling: possible. 2074 */ 2075 int rtdm_munmap(rtdm_user_info_t *user_info, void *ptr, size_t len) 2076 { 2077 int err; 2078 2079 RTAI_ASSERT(RTDM, xnpod_root_p(), return -EPERM;); 2080 2081 down_write(&user_info->mm->mmap_sem); 2082 err = do_munmap(user_info->mm, (unsigned long)ptr, len); 2083 up_write(&user_info->mm->mmap_sem); 2084 2085 return err; 2086 } 2087 2088 EXPORT_SYMBOL(rtdm_munmap); 2089 2090 2091 #ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */ 2092 2093 /** 2094 * Real-time safe message printing on kernel console 2095 * 2096 * @param[in] format Format string (conforming standard @c printf()) 2097 * @param ... Arguments referred by @a format 2098 * 2099 * @return On success, this service returns the number of characters printed. 2100 * Otherwise, a negative error code is returned. 2101 * 2102 * Environments: 2103 * 2104 * This service can be called from: 2105 * 2106 * - Kernel module initialization/cleanup code 2107 * - Interrupt service routine (consider the overhead!) 2108 * - Kernel-based task 2109 * - User-space task (RT, non-RT) 2110 * 2111 * Rescheduling: never in real-time context, possible in non-real-time 2112 * environments. 2113 */ 2114 void rtdm_printk(const char *format, ...); 2115 2116 /** 2117 * Allocate memory block in real-time context 2118 * 2119 * @param[in] size Requested size of the memory block 2120 * 2121 * @return The pointer to the allocated block is returned on success, NULL 2122 * otherwise. 2123 * 2124 * Environments: 2125 * 2126 * This service can be called from: 2127 * 2128 * - Kernel module initialization/cleanup code 2129 * - Interrupt service routine (consider the overhead!) 2130 * - Kernel-based task 2131 * - User-space task (RT, non-RT) 2132 * 2133 * Rescheduling: never. 2134 */ 2135 void *rtdm_malloc(size_t size); 2136 2137 /** 2138 * Release real-time memory block 2139 * 2140 * @param[in] ptr Pointer to memory block as returned by rtdm_malloc() 2141 * 2142 * Environments: 2143 * 2144 * This service can be called from: 2145 * 2146 * - Kernel module initialization/cleanup code 2147 * - Interrupt service routine (consider the overhead!) 2148 * - Kernel-based task 2149 * - User-space task (RT, non-RT) 2150 * 2151 * Rescheduling: never. 2152 */ 2153 void rtdm_free(void *ptr); 2154 2155 /** 2156 * Check if read access to user-space memory block is safe 2157 * 2158 * @param[in] user_info User information pointer as passed to the invoked 2159 * device operation handler 2160 * @param[in] ptr Address of the user-provided memory block 2161 * @param[in] size Size of the memory block 2162 * 2163 * @return Non-zero is return when it is safe to read from the specified 2164 * memory block, 0 otherwise. 2165 * 2166 * Environments: 2167 * 2168 * This service can be called from: 2169 * 2170 * - Kernel module initialization/cleanup code 2171 * - Kernel-based task 2172 * - User-space task (RT, non-RT) 2173 * 2174 * Rescheduling: never. 2175 */ 2176 int rtdm_read_user_ok(rtdm_user_info_t *user_info, const void __user *ptr, 2177 size_t size); 2178 2179 /** 2180 * Check if read/write access to user-space memory block is safe 2181 * 2182 * @param[in] user_info User information pointer as passed to the invoked 2183 * device operation handler 2184 * @param[in] ptr Address of the user-provided memory block 2185 * @param[in] size Size of the memory block 2186 * 2187 * @return Non-zero is return when it is safe to read from or write to the 2188 * specified memory block, 0 otherwise. 2189 * 2190 * Environments: 2191 * 2192 * This service can be called from: 2193 * 2194 * - Kernel module initialization/cleanup code 2195 * - Kernel-based task 2196 * - User-space task (RT, non-RT) 2197 * 2198 * Rescheduling: never. 2199 */ 2200 int rtdm_rw_user_ok(rtdm_user_info_t *user_info, const void __user *ptr, 2201 size_t size); 2202 2203 /** 2204 * Copy user-space memory block to specified buffer 2205 * 2206 * @param[in] user_info User information pointer as passed to the invoked 2207 * device operation handler 2208 * @param[in] dst Destination buffer address 2209 * @param[in] src Address of the user-space memory block 2210 * @param[in] size Size of the memory block 2211 * 2212 * @return 0 on success, otherwise: 2213 * 2214 * - -EFAULT is returned if an invalid memory area was accessed. 2215 * 2216 * @note Before invoking this service, verify via rtdm_read_user_ok() that the 2217 * provided user-space address can securely be accessed. 2218 * 2219 * Environments: 2220 * 2221 * This service can be called from: 2222 * 2223 * - Kernel module initialization/cleanup code 2224 * - Kernel-based task 2225 * - User-space task (RT, non-RT) 2226 * 2227 * Rescheduling: never. 2228 */ 2229 int rtdm_copy_from_user(rtdm_user_info_t *user_info, void *dst, 2230 const void __user *src, size_t size); 2231 2232 /** 2233 * Check if read access to user-space memory block and copy it to specified 2234 * buffer 2235 * 2236 * @param[in] user_info User information pointer as passed to the invoked 2237 * device operation handler 2238 * @param[in] dst Destination buffer address 2239 * @param[in] src Address of the user-space memory block 2240 * @param[in] size Size of the memory block 2241 * 2242 * @return 0 on success, otherwise: 2243 * 2244 * - -EFAULT is returned if an invalid memory area was accessed. 2245 * 2246 * @note This service is a combination of rtdm_read_user_ok and 2247 * rtdm_copy_from_user. 2248 * 2249 * Environments: 2250 * 2251 * This service can be called from: 2252 * 2253 * - Kernel module initialization/cleanup code 2254 * - Kernel-based task 2255 * - User-space task (RT, non-RT) 2256 * 2257 * Rescheduling: never. 2258 */ 2259 int rtdm_safe_copy_from_user(rtdm_user_info_t *user_info, void *dst, 2260 const void __user *src, size_t size); 2261 2262 /** 2263 * Copy specified buffer to user-space memory block 2264 * 2265 * @param[in] user_info User information pointer as passed to the invoked 2266 * device operation handler 2267 * @param[in] dst Address of the user-space memory block 2268 * @param[in] src Source buffer address 2269 * @param[in] size Size of the memory block 2270 * 2271 * @return 0 on success, otherwise: 2272 * 2273 * - -EFAULT is returned if an invalid memory area was accessed. 2274 * 2275 * @note Before invoking this service, verify via rtdm_rw_user_ok() that the 2276 * provided user-space address can securely be accessed. 2277 * 2278 * Environments: 2279 * 2280 * This service can be called from: 2281 * 2282 * - Kernel module initialization/cleanup code 2283 * - Kernel-based task 2284 * - User-space task (RT, non-RT) 2285 * 2286 * Rescheduling: never. 2287 */ 2288 int rtdm_copy_to_user(rtdm_user_info_t *user_info, void __user *dst, 2289 const void *src, size_t size); 2290 2291 /** 2292 * Check if read/write access to user-space memory block is safe and copy 2293 * specified buffer to it 2294 * 2295 * @param[in] user_info User information pointer as passed to the invoked 2296 * device operation handler 2297 * @param[in] dst Address of the user-space memory block 2298 * @param[in] src Source buffer address 2299 * @param[in] size Size of the memory block 2300 * 2301 * @return 0 on success, otherwise: 2302 * 2303 * - -EFAULT is returned if an invalid memory area was accessed. 2304 * 2305 * @note This service is a combination of rtdm_rw_user_ok and 2306 * rtdm_copy_to_user. 2307 * 2308 * Environments: 2309 * 2310 * This service can be called from: 2311 * 2312 * - Kernel module initialization/cleanup code 2313 * - Kernel-based task 2314 * - User-space task (RT, non-RT) 2315 * 2316 * Rescheduling: never. 2317 */ 2318 int rtdm_safe_copy_to_user(rtdm_user_info_t *user_info, void __user *dst, 2319 const void *src, size_t size); 2320 2321 /** 2322 * Copy user-space string to specified buffer 2323 * 2324 * @param[in] user_info User information pointer as passed to the invoked 2325 * device operation handler 2326 * @param[in] dst Destination buffer address 2327 * @param[in] src Address of the user-space string 2328 * @param[in] count Maximum number of bytes to copy, including the trailing 2329 * '0' 2330 * 2331 * @return Length of the string on success (not including the trailing '0'), 2332 * otherwise: 2333 * 2334 * - -EFAULT is returned if an invalid memory area was accessed. 2335 * 2336 * @note This services already includes a check of the source address, 2337 * calling rtdm_read_user_ok() for @a src explicitly is not required. 2338 * 2339 * Environments: 2340 * 2341 * This service can be called from: 2342 * 2343 * - Kernel module initialization/cleanup code 2344 * - Kernel-based task 2345 * - User-space task (RT, non-RT) 2346 * 2347 * Rescheduling: never. 2348 */ 2349 int rtdm_strncpy_from_user(rtdm_user_info_t *user_info, char *dst, 2350 const char __user *src, size_t count); 2351 2352 /** 2353 * Test if running in a real-time task 2354 * 2355 * @return Non-zero is returned if the caller resides in real-time context, 0 2356 * otherwise. 2357 * 2358 * Environments: 2359 * 2360 * This service can be called from: 2361 * 2362 * - Kernel module initialization/cleanup code 2363 * - Kernel-based task 2364 * - User-space task (RT, non-RT) 2365 * 2366 * Rescheduling: never. 2367 */ 2368 int rtdm_in_rt_context(void); 2369 2370 #endif /* DOXYGEN_CPP */ 2371 2372 /** @} Utility Services */