Esempio n. 1
0
/*!
 * \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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/*!
 * \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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
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;
}
Esempio n. 6
0
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;
}