📄 intr.c
字号:
/** * @file * This file is part of the Xenomai project. * * @note Copyright (C) 2005 Philippe Gerum <rpm@xenomai.org> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * \ingroup interrupt *//*! * \ingroup native * \defgroup interrupt Interrupt management services. * *@{*/#include <nucleus/pod.h>#include <nucleus/registry.h>#include <native/task.h>#include <native/intr.h>static DECLARE_XNQUEUE(__xeno_intr_q);int __native_intr_pkg_init (void){ return 0;}void __native_intr_pkg_cleanup (void){ xnholder_t *holder; while ((holder = getheadq(&__xeno_intr_q)) != NULL) rt_intr_delete(link2intr(holder));}#ifdef CONFIG_XENO_EXPORT_REGISTRYstatic int __intr_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ RT_INTR *intr = (RT_INTR *)data; char *p = page; int len;#ifdef CONFIG_XENO_OPT_PERVASIVE { xnpholder_t *holder; spl_t s; xnlock_get_irqsave(&nklock,s); p += sprintf(p,"hits=%lu, pending=%u, mode=0x%x\n", intr->intr_base.hits, intr->pending, intr->mode); /* Pended interrupt -- dump waiters. */ holder = getheadpq(xnsynch_wait_queue(&intr->synch_base)); while (holder) { xnthread_t *sleeper = link2thread(holder,plink); p += sprintf(p,"+%s\n",xnthread_name(sleeper)); holder = nextpq(xnsynch_wait_queue(&intr->synch_base),holder); } xnlock_put_irqrestore(&nklock,s); }#else /* !CONFIG_XENO_OPT_PERVASIVE */ p += sprintf(p,"hits=%lu\n",intr->intr_base.hits);#endif /* CONFIG_XENO_OPT_PERVASIVE */ len = (p - page) - off; if (len <= off + count) *eof = 1; *start = page + off; if(len > count) len = count; if(len < 0) len = 0; return len;}extern xnptree_t __native_ptree;static xnpnode_t __intr_pnode = { .dir = NULL, .type = "interrupts", .entries = 0, .read_proc = &__intr_read_proc, .write_proc = NULL, .root = &__native_ptree,};#elif defined(CONFIG_XENO_OPT_REGISTRY)static xnpnode_t __intr_pnode = { .type = "interrupts"};#endif /* CONFIG_XENO_EXPORT_REGISTRY *//*! * \fn int rt_intr_create (RT_INTR *intr,const char *name,unsigned irq,rt_isr_t isr,rt_iack_t iack,int mode) * \brief Create an interrupt object from kernel space. * * Initializes and associates an interrupt object with an IRQ line. In * kernel space, interrupts are immediately notified to a user-defined * handler or ISR (interrupt service routine). * * When an interrupt occurs on the given @a irq line, the ISR is fired * in order to deal with the hardware event. The interrupt service * code may call any non-suspensive Xenomai service. * * Upon receipt of an IRQ, the ISR is immediately called on behalf of * the interrupted stack context, the rescheduling procedure is * locked, and the interrupt source is masked at hardware level. The * status value returned by the ISR is then checked for the following * values: * * - RT_INTR_HANDLED indicates that the interrupt request has been fulfilled * by the ISR. * * - RT_INTR_NONE indicates the opposite to RT_INTR_HANDLED. The ISR must always * return this value when it determines that the interrupt request has not been * issued by the dedicated hardware device. * * In addition, one of the following bits may be set by the ISR : * * NOTE: use these bits with care and only when you do understand their effect * on the system. * The ISR is not encouraged to use these bits in case it shares the IRQ line * with other ISRs in the real-time domain. * * - RT_INTR_PROPAGATE tells Xenomai to require the real-time control * layer to forward the IRQ. For instance, this would cause the Adeos * control layer to propagate the interrupt down the interrupt * pipeline to other Adeos domains, such as Linux. This is the regular * way to share interrupts between Xenomai and the Linux kernel. * * - RT_INTR_NOENABLE asks Xenomai not to re-enable the IRQ line upon return * of the interrupt service routine. * * A count of interrupt receipts is tracked into the interrupt * descriptor, and reset to zero each time the interrupt object is * attached. Since this count could wrap around, it should be used as * an indication of interrupt activity only. * * @param intr The address of a interrupt object descriptor Xenomai will * use to store the object-specific data. This descriptor must always * be valid while the object is active therefore it must be allocated * in permanent memory. * * @param name An ASCII string standing for the symbolic name of the * interrupt object. When non-NULL and non-empty, this string is copied * to a safe place into the descriptor, and passed to the registry package * if enabled for indexing the created interrupt objects. * * @param irq The hardware interrupt channel associated with the * interrupt object. This value is architecture-dependent. * * @param isr The address of a valid interrupt service routine in * kernel space. This handler will be called each time the * corresponding IRQ is delivered on behalf of an interrupt context. * A pointer to an internal information is passed to the routine which * can use it to retrieve the descriptor address of the associated * interrupt object through the I_DESC() macro. * * @param iack The address of an optional interrupt acknowledge * routine, aimed at replacing the default one. Only very specific * situations actually require to override the default setting for * this parameter, like having to acknowledge non-standard PIC * hardware. @a iack should return a non-zero value to indicate that * the interrupt has been properly acknowledged. If @a iack is NULL, * the default routine will be used instead. * * @param mode The interrupt object creation mode. The following flags can be * OR'ed into this bitmask, each of them affecting the new interrupt object: * * - I_SHARED enables IRQ-sharing with other interrupt objects. * * - I_EDGE is an additional flag need to be set together with I_SHARED * to enable IRQ-sharing of edge-triggered interrupts. * * @return 0 is returned upon success. Otherwise: * * - -ENOMEM is returned if the system fails to get enough dynamic * memory from the global real-time heap in order to register the * interrupt object. * * - -EBUSY is returned if the interrupt line is already in use by * another interrupt object. Only a single interrupt object can be * associated to any given interrupt line using rt_intr_create() at * any time. * * - -EEXIST is returned if @a irq is already associated to an * existing interrupt object. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * * Rescheduling: possible. * * @note The interrupt source associated to the interrupt descriptor * remains masked upon creation. rt_intr_enable() should be called for * the new interrupt object to unmask it. */int rt_intr_create (RT_INTR *intr, const char *name, unsigned irq, rt_isr_t isr, rt_iack_t iack, int mode){ int err; spl_t s; if (xnpod_asynch_p()) return -EPERM; xnintr_init(&intr->intr_base,name,irq,isr,iack,mode); xnobject_copy_name(intr->name,name);#if defined(__KERNEL__) && defined(CONFIG_XENO_OPT_PERVASIVE) xnsynch_init(&intr->synch_base,XNSYNCH_PRIO); intr->pending = 0; intr->cpid = 0; intr->mode = 0;#endif /* __KERNEL__ && CONFIG_XENO_OPT_PERVASIVE */ intr->magic = XENO_INTR_MAGIC; intr->handle = 0; /* i.e. (still) unregistered interrupt. */ inith(&intr->link); xnlock_get_irqsave(&nklock,s); appendq(&__xeno_intr_q,&intr->link); xnlock_put_irqrestore(&nklock,s); err = xnintr_attach(&intr->intr_base,intr);#ifdef CONFIG_XENO_OPT_REGISTRY /* <!> Since xnregister_enter() may reschedule, only register complete objects, so that the registry cannot return handles to half-baked objects... */ if (!err) err = xnregistry_enter(intr->name,intr,&intr->handle,&__intr_pnode);#endif /* CONFIG_XENO_OPT_REGISTRY */ if (err) rt_intr_delete(intr); return err;}/** * @fn int rt_intr_delete(RT_INTR *intr) * @brief Delete an interrupt object. * * Destroys an interrupt object. An interrupt exists in the system * since rt_intr_create() has been called to create it, so this * service must be called in order to destroy it afterwards. * * Any user-space task which might be currently pending on the * interrupt object through the rt_intr_wait() service will be awaken * as a result of the deletion, and return with the -EIDRM status. * * @param intr The descriptor address of the affected interrupt object. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a intr is not a interrupt object * descriptor. * * - -EIDRM is returned if @a intr is a deleted interrupt object * descriptor. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_intr_delete (RT_INTR *intr){ int err = 0, rc = XNSYNCH_DONE; spl_t s; if (xnpod_asynch_p()) return -EPERM; xnlock_get_irqsave(&nklock,s); intr = xeno_h2obj_validate(intr,XENO_INTR_MAGIC,RT_INTR); if (!intr) { err = xeno_handle_error(intr,XENO_INTR_MAGIC,RT_INTR); goto unlock_and_exit; } removeq(&__xeno_intr_q,&intr->link);#if defined(__KERNEL__) && defined(CONFIG_XENO_OPT_PERVASIVE) rc = xnsynch_destroy(&intr->synch_base);#endif /* __KERNEL__ && CONFIG_XENO_OPT_PERVASIVE */ xnintr_detach(&intr->intr_base);#ifdef CONFIG_XENO_OPT_REGISTRY if (intr->handle) xnregistry_remove(intr->handle);#endif /* CONFIG_XENO_OPT_REGISTRY */ xnintr_destroy(&intr->intr_base); xeno_mark_deleted(intr); if (rc == XNSYNCH_RESCHED) /* Some task has been woken up as a result of the deletion: reschedule now. */ xnpod_schedule(); unlock_and_exit: xnlock_put_irqrestore(&nklock,s); return err;}/*! * \fn int rt_intr_enable (RT_INTR *intr) * \brief Enable an interrupt object. * * Enables the hardware interrupt line associated with an interrupt * object. Over Adeos-based systems which mask and acknowledge IRQs * upon receipt, this operation is necessary to revalidate the * interrupt channel so that more interrupts from the same source can * be notified.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -