return !action;
}
-/*
- * Internal function to register an irqaction - typically used to
- * allocate special interrupts that are part of the architecture.
+/**
+ * setup_irq - register an irqaction structure
+ * @irq: Interrupt to register
+ * @irqaction: The irqaction structure to be registered
+ *
+ * Normally called by request_irq, this function can be used
+ * directly to allocate special interrupts that are part of the
+ * architecture.
*/
int setup_irq(unsigned int irq, struct irqaction * new)
{
return 0;
}
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
+/*
+ * teardown_irq - unregister an irqaction
+ * @irq: Interrupt line being freed
+ * @old: Pointer to the irqaction that is to be unregistered
*
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
+ * This function is called by free_irq and does the actual
+ * business of unregistering the handler. It exists as a
+ * seperate function to enable handlers to be unregistered
+ * for irqactions that have been allocated statically at
+ * boot time.
*
* This function must not be called from interrupt context.
*/
-void free_irq(unsigned int irq, void *dev_id)
+int teardown_irq(unsigned int irq, struct irqaction * old)
{
struct irq_desc *desc;
struct irqaction **p;
unsigned long flags;
if (irq >= NR_IRQS)
- return;
+ return -ENOENT;
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock,flags);
struct irqaction **pp = p;
p = &action->next;
- if (action->dev_id != dev_id)
+ if (action != old)
continue;
/* Found it - now remove it from the list of entries */
/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
- kfree(action);
- return;
+ return 0;
}
- printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ printk(KERN_ERR "Trying to teardown free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -ENOENT;
+ }
+}
+
+/**
+ * free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction *action;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ for (action = desc->action; action != NULL; action = action->next) {
+ if (action->dev_id != dev_id)
+ continue;
+
spin_unlock_irqrestore(&desc->lock,flags);
+
+ if (teardown_irq(irq, action) == 0)
+ kfree(action);
return;
}
+ printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
}
EXPORT_SYMBOL(free_irq);