drvlib.c
来自「xenomai 很好的linux实时补丁」· C语言 代码 · 共 1,740 行 · 第 1/3 页
C
1,740 行
/** * @file * Real-Time Driver Model for Xenomai, driver library * * @note Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de> * @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net> * * Xenomai is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Xenomai is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Xenomai; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*! * @ingroup rtdm * @defgroup driverapi Driver Development API * * This is the lower interface of RTDM provided to device drivers, currently * limited to kernel-space. Real-time drivers should only use functions of * this interface in order to remain portable. */#include <asm/io.h>#include <linux/delay.h>#include <linux/mman.h>#include <rtdm/rtdm_driver.h>/*! * @ingroup driverapi * @defgroup clock Clock Services * @{ */#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation *//** * @brief Get system time * * @return The system time in nanoseconds is returned * * @note The nucleus timer has to be started to obtain valid results. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */uint64_t rtdm_clock_read(void);#endif /* DOXYGEN_CPP *//** @} *//*! * @ingroup driverapi * @defgroup rtdmtask Task Services * @{ *//** * @brief Intialise and start a real-time task * * @param[in,out] task Task handle * @param[in] name Optional task name * @param[in] task_proc Procedure to be executed by the task * @param[in] arg Custom argument passed to @c task_proc() on entry * @param[in] priority Priority of the task, see also * @ref taskprio "Task Priority Range" * @param[in] period Period in nanosecons of a cyclic task, 0 for non-cyclic * mode * * @return 0 on success, otherwise negative error code * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */int rtdm_task_init(rtdm_task_t *task, const char *name, rtdm_task_proc_t task_proc, void *arg, int priority, uint64_t period){ int res; res = xnpod_init_thread(task, name, priority, 0, 0); if (res) goto error_out; if (period != XN_INFINITE) { res = xnpod_set_thread_periodic(task, XN_INFINITE, xnpod_ns2ticks(period)); if (res) goto cleanup_out; } res = xnpod_start_thread(task, 0, 0, XNPOD_ALL_CPUS, task_proc, arg); if (res) goto cleanup_out; return res; cleanup_out: xnpod_delete_thread(task); error_out: return res;}EXPORT_SYMBOL(rtdm_task_init);#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation *//** * @brief Destroy a real-time task * * @param[in,out] task Task handle as returned by rtdm_task_init() * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */void rtdm_task_destroy(rtdm_task_t *task);/** * @brief Adjust real-time task priority * * @param[in,out] task Task handle as returned by rtdm_task_init() * @param[in] priority New priority of the task, see also * @ref taskprio "Task Priority Range" * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */void rtdm_task_set_priority(rtdm_task_t *task, int priority);/** * @brief Adjust real-time task period * * @param[in,out] task Task handle as returned by rtdm_task_init() * @param[in] period New period in nanosecons of a cyclic task, 0 for * non-cyclic mode * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */int rtdm_task_set_period(rtdm_task_t *task, uint64_t period);/** * @brief Wait on next real-time task period * * @return 0 on success, otherwise: * * - -EINVAL is returned if calling task is not in periodic mode. * * - -ETIMEDOUT is returned if a timer overrun occurred, which indicates * that a previous release point has been missed by the calling task. * * Environments: * * This service can be called from: * * - Kernel-based task * - User-space task (RT) * * Rescheduling: always, unless a timer overrun occured. */int rtdm_task_wait_period(void);/** * @brief Activate a blocked real-time task * * @return Non-zero is returned if the task was actually unblocked from a * pending wait state, 0 otherwise. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */int rtdm_task_unblock(rtdm_task_t *task);/** * @brief Get current real-time task * * @return Pointer to task handle * * Environments: * * This service can be called from: * * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */rtdm_task_t *rtdm_task_current(void);#endif /* DOXYGEN_CPP *//** * @brief Wait on a real-time task to terminate * * @param[in,out] task Task handle as returned by rtdm_task_init() * @param[in] poll_delay Polling delay in milliseconds * * @note It is not required to call rtdm_task_destroy() for a task which has * been passed to rtdm_task_join_nrt(). Moreover, don't forget to inform the * targeted task that it has to terminate. Otherwise, this function will never * return. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - User-space task (non-RT) * * Rescheduling: possible. */void rtdm_task_join_nrt(rtdm_task_t *task, unsigned int poll_delay){ spl_t s; xnlock_get_irqsave(&nklock, s); while (!xnthread_test_flags(task, XNZOMBIE)) { xnlock_put_irqrestore(&nklock, s); msleep(poll_delay); xnlock_get_irqsave(&nklock, s); } xnlock_put_irqrestore(&nklock, s);}EXPORT_SYMBOL(rtdm_task_join_nrt);/** * @brief Sleep a specified amount of time * * @param[in] delay Delay in nanoseconds * * @return 0 on success, otherwise: * * - -EINTR is returned if calling task has been unblock by a signal or * explicitely via rtdm_task_unblock(). * * Environments: * * This service can be called from: * * - Kernel-based task * - User-space task (RT) * * Rescheduling: always. */int rtdm_task_sleep(uint64_t delay){ xnthread_t *thread = xnpod_current_thread(); xnpod_suspend_thread(thread, XNDELAY, xnpod_ns2ticks(delay), NULL); return xnthread_test_flags(thread, XNBREAK) ? -EINTR : 0;}EXPORT_SYMBOL(rtdm_task_sleep);/** * @brief Sleep until a specified absolute time * * @param[in] wakeup_time Absolute timeout in nanoseconds * * @return 0 on success, otherwise: * * - -EINTR is returned if calling task has been unblock by a signal or * explicitely via rtdm_task_unblock(). * * Environments: * * This service can be called from: * * - Kernel-based task * - User-space task (RT) * * Rescheduling: always, unless the specified time already passed. */int rtdm_task_sleep_until(uint64_t wakeup_time){ xnthread_t *thread = xnpod_current_thread(); xnsticks_t delay; spl_t s; int err = 0; xnlock_get_irqsave(&nklock, s); delay = xnpod_ns2ticks(wakeup_time) - xnpod_get_time(); if (likely(delay > 0)) { xnpod_suspend_thread(thread, XNDELAY, delay, NULL); if (xnthread_test_flags(thread, XNBREAK)) err = -EINTR; } xnlock_put_irqrestore(&nklock, s); return err;}EXPORT_SYMBOL(rtdm_task_sleep_until);/** * @brief Busy-wait a specified amount of time * * @param[in] delay Delay in nanoseconds * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine (but you should rather avoid this...) * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */void rtdm_task_busy_sleep(uint64_t delay){ xnticks_t wakeup = xnarch_get_cpu_tsc() + xnarch_ns_to_tsc(delay); while (xnarch_get_cpu_tsc() < wakeup) cpu_relax();}EXPORT_SYMBOL(rtdm_task_busy_sleep);/** @} *//* --- IPC cleanup helper --- */#define SYNCH_DELETED XNSYNCH_SPARE0void _rtdm_synch_flush(xnsynch_t *synch, unsigned long reason){ spl_t s; xnlock_get_irqsave(&nklock,s); if (reason == XNRMID) setbits(synch->status, SYNCH_DELETED); if (likely(xnsynch_flush(synch, reason) == XNSYNCH_RESCHED)) xnpod_schedule(); xnlock_put_irqrestore(&nklock, s);}EXPORT_SYMBOL(_rtdm_synch_flush);/*! * @ingroup driverapi * @defgroup rtdmsync Synchronisation Services * @{ *//*! * @name Timeout Sequence Management * @{ */#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation *//** * @brief Initialise a timeout sequence * * This service initialises a timeout sequence handle according to the given * timeout value. Timeout sequences allow to maintain a continuous @a timeout * across multiple calls of blocking synchronisation services. A typical * application scenario is given below. * * @param[in,out] timeout_seq Timeout sequence handle * @param[in] timeout Relative timeout in nanoseconds, 0 for infinite, or any * negative value for non-blocking * * Application Scenario: * @codeint device_service_routine(...){ rtdm_toseq_t timeout_seq; ... rtdm_toseq_init(&timeout_seq, timeout); ... while (received < requested) { ret = rtdm_event_timedwait(&data_available, timeout, &timeout_seq); if (ret < 0) // including -ETIMEDOUT break; // receive some data ... } ...} * @endcode * Using a timeout sequence in such a scenario avoids that the user-provided * relative @c timeout is restarted on every call to rtdm_event_timedwait(), * potentially causing an overall delay that is larger than specified by * @c timeout. Moreover, all functions supporting timeout sequences also * interpret special timeout values (infinite and non-blocking), * disburdening the driver developer from handling them separately. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */void rtdm_toseq_init(rtdm_toseq_t *timeout_seq, int64_t timeout);#endif /* DOXYGEN_CPP *//** @} *//*! * @name Event Services * @{ */#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation *//** * @brief Initialise an event * * @param[in,out] event Event handle * @param[in] pending Non-zero if event shall be initialised as set, 0 otherwise * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */void rtdm_event_init(rtdm_event_t *event, unsigned long pending);/** * @brief Destroy an event * * @param[in,out] event Event handle as returned by rtdm_event_init() * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */void rtdm_event_destroy(rtdm_event_t *event);/** * @brief Signal an event occurrence to currently listening waiters * * This function wakes up all current waiters of the given event, but it does * not change the event state. Subsequently callers of rtdm_event_wait() or * rtdm_event_wait_until() will therefore be blocked first. * * @param[in,out] event Event handle as returned by rtdm_event_init() * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: possible. */void rtdm_event_pulse(rtdm_event_t *event);/** * @brief Clear event state * * @param[in,out] event Event handle as returned by rtdm_event_init() * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task (RT, non-RT) * * Rescheduling: never. */void rtdm_event_clear(rtdm_event_t *event);#endif /* DOXYGEN_CPP *//** * @brief Signal an event occurrence * * This function sets the given event and wakes up all current waiters. If no * waiter is presently registered, the next call to rtdm_event_wait() or * rtdm_event_wait_until() will return immediately. * * @param[in,out] event Event handle as returned by rtdm_event_init() * * Environments:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?