/*! * \fn int xnintr_detach (xnintr_t *intr) * \brief Detach an interrupt object. * * Detach an interrupt object previously attached by * xnintr_attach(). After this operation is completed, no more IRQs * are directed to the object's ISR, but the interrupt object itself * remains valid. A detached interrupt object can be attached again by * a subsequent call to xnintr_attach(). * * @param intr The descriptor address of the interrupt object to * detach. * * @return 0 is returned on success. Otherwise: * * - -EINVAL is returned if a low-level error occurred while detaching * the interrupt, or if the interrupt object was not attached. In both * cases, no action is performed. * * @note The caller <b>must not</b> hold nklock when invoking this service, * this would cause deadlocks. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * * Rescheduling: never. */ int xnintr_detach(xnintr_t *intr) { int ret; trace_mark(xn_nucleus, irq_detach, "irq %u", intr->irq); down(&intrlock); if (!__testbits(intr->flags, XN_ISR_ATTACHED)) { ret = -EINVAL; goto out; } __clrbits(intr->flags, XN_ISR_ATTACHED); ret = xnintr_irq_detach(intr); if (ret) goto out; xnintr_stat_counter_dec(); out: up(&intrlock); return ret; }
int xnintr_attach(xnintr_t *intr, void *cookie) { int ret; trace_mark(xn_nucleus, irq_attach, "irq %u name %s", intr->irq, intr->name); intr->cookie = cookie; memset(&intr->stat, 0, sizeof(intr->stat)); #ifdef CONFIG_SMP xnarch_set_irq_affinity(intr->irq, nkaffinity); #endif /* CONFIG_SMP */ down(&intrlock); if (__testbits(intr->flags, XN_ISR_ATTACHED)) { ret = -EBUSY; goto out; } ret = xnintr_irq_attach(intr); if (ret) goto out; __setbits(intr->flags, XN_ISR_ATTACHED); xnintr_stat_counter_inc(); out: up(&intrlock); return ret; }
/*! * \fn int xnintr_detach (xnintr_t *intr) * \brief Detach an interrupt object. * * Detach an interrupt object previously attached by * xnintr_attach(). After this operation is completed, no more IRQs * are directed to the object's ISR, but the interrupt object itself * remains valid. A detached interrupt object can be attached again by * a subsequent call to xnintr_attach(). * * @param intr The descriptor address of the interrupt object to * detach. * * @return 0 is returned on success. Otherwise: * * - -EINVAL is returned if a low-level error occurred while detaching * the interrupt, or if the interrupt object was not attached. In both * cases, no action is performed. * * @note The caller <b>must not</b> hold nklock when invoking this service, * this would cause deadlocks. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * * Rescheduling: never. */ int xnintr_detach(xnintr_t *intr) { int ret; spl_t s; trace_mark(xn_nucleus, irq_detach, "irq %u", intr->irq); xnlock_get_irqsave(&intrlock, s); if (!__testbits(intr->flags, XN_ISR_ATTACHED)) { ret = -EINVAL; goto out; } __clrbits(intr->flags, XN_ISR_ATTACHED); ret = xnintr_irq_detach(intr); if (ret) goto out; xnintr_stat_counter_dec(); out: xnlock_put_irqrestore(&intrlock, s); return ret; }
static inline int xnintr_irq_attach(xnintr_t *intr) { xnintr_irq_t *shirq = &xnirqs[intr->irq]; xnintr_t *prev, **p = &shirq->handlers; int err; if (intr->irq >= RTHAL_NR_IRQS) return -EINVAL; if (__testbits(intr->flags, XN_ISR_ATTACHED)) return -EPERM; if ((prev = *p) != NULL) { /* Check on whether the shared mode is allowed. */ if (!(prev->flags & intr->flags & XN_ISR_SHARED) || (prev->iack != intr->iack) || ((prev->flags & XN_ISR_EDGE) != (intr->flags & XN_ISR_EDGE))) return -EBUSY; /* Get a position at the end of the list to insert the new element. */ while (prev) { p = &prev->next; prev = *p; } } else { /* Initialize the corresponding interrupt channel */ void (*handler) (unsigned, void *) = &xnintr_irq_handler; if (intr->flags & XN_ISR_SHARED) { if (intr->flags & XN_ISR_EDGE) handler = &xnintr_edge_shirq_handler; else handler = &xnintr_shirq_handler; } shirq->unhandled = 0; err = xnarch_hook_irq(intr->irq, handler, intr->iack, intr); if (err) return err; } __setbits(intr->flags, XN_ISR_ATTACHED); intr->next = NULL; /* Add the given interrupt object. No need to synchronise with the IRQ handler, we are only extending the chain. */ *p = intr; return 0; }
int xnintr_attach(xnintr_t *intr, void *cookie) { int ret; spl_t s; trace_mark(xn_nucleus, irq_attach, "irq %u name %s", intr->irq, intr->name); intr->cookie = cookie; memset(&intr->stat, 0, sizeof(intr->stat)); #ifdef CONFIG_SMP xnarch_set_irq_affinity(intr->irq, nkaffinity); #endif /* CONFIG_SMP */ xnlock_get_irqsave(&intrlock, s); if (intr->irq >= XNARCH_NR_IRQS) { ret = -EINVAL; goto out; } if (__testbits(intr->flags, XN_ISR_ATTACHED)) { ret = -EBUSY; goto out; } ret = xnintr_irq_attach(intr); if (ret) goto out; __setbits(intr->flags, XN_ISR_ATTACHED); xnintr_stat_counter_inc(); out: xnlock_put_irqrestore(&intrlock, s); return ret; }
static inline int xnintr_irq_detach(xnintr_t *intr) { xnintr_irq_t *shirq = &xnirqs[intr->irq]; xnintr_t *e, **p = &shirq->handlers; int err = 0; if (intr->irq >= RTHAL_NR_IRQS) return -EINVAL; if (!__testbits(intr->flags, XN_ISR_ATTACHED)) return -EPERM; __clrbits(intr->flags, XN_ISR_ATTACHED); while ((e = *p) != NULL) { if (e == intr) { /* Remove the given interrupt object from the list. */ xnlock_get(&shirq->lock); *p = e->next; xnlock_put(&shirq->lock); /* Release the IRQ line if this was the last user */ if (shirq->handlers == NULL) err = xnarch_release_irq(intr->irq); return err; } p = &e->next; } xnlogerr("attempted to detach a non previously attached interrupt " "object.\n"); return err; }