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 + -
显示快捷键?