diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-03-12 08:05:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-12 08:16:32 -0400 |
commit | f21cfb258df6dd3ea0b3e56d75c7e994edb81b35 (patch) | |
tree | 63d2c11d1857bdffab6bf3ed036af8e03d16abd7 | |
parent | f8cb22cbb8383c9f41e6ccbcd4fb94edb1048bda (diff) |
irq: add remove_irq() for freeing of setup_irq() irqs
Impact: add new API
This patch adds a remove_irq() function for releasing
interrupts requested with setup_irq().
Without this patch we have no way of releasing such
interrupts since free_irq() today tries to kfree()
the irqaction passed with setup_irq().
Signed-off-by: Magnus Damm <damm@igel.co.jp>
LKML-Reference: <20090312120542.2926.56609.sendpatchset@rx1.opensource.se>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | include/linux/irq.h | 1 | ||||
-rw-r--r-- | kernel/irq/manage.c | 39 |
2 files changed, 27 insertions, 13 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index f899b502f186..56f9988362ec 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -236,6 +236,7 @@ typedef struct irq_desc irq_desc_t; | |||
236 | #include <asm/hw_irq.h> | 236 | #include <asm/hw_irq.h> |
237 | 237 | ||
238 | extern int setup_irq(unsigned int irq, struct irqaction *new); | 238 | extern int setup_irq(unsigned int irq, struct irqaction *new); |
239 | extern struct irqaction *remove_irq(unsigned int irq, void *dev_id); | ||
239 | 240 | ||
240 | #ifdef CONFIG_GENERIC_HARDIRQS | 241 | #ifdef CONFIG_GENERIC_HARDIRQS |
241 | 242 | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 52ee17135092..8b069a7046e9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -551,20 +551,14 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
551 | } | 551 | } |
552 | 552 | ||
553 | /** | 553 | /** |
554 | * free_irq - free an interrupt | 554 | * remove_irq - free an interrupt |
555 | * @irq: Interrupt line to free | 555 | * @irq: Interrupt line to free |
556 | * @dev_id: Device identity to free | 556 | * @dev_id: Device identity to free |
557 | * | 557 | * |
558 | * Remove an interrupt handler. The handler is removed and if the | 558 | * Used to remove interrupts statically setup by the early boot process. |
559 | * interrupt line is no longer in use by any driver it is disabled. | ||
560 | * On a shared IRQ the caller must ensure the interrupt is disabled | ||
561 | * on the card it drives before calling this function. The function | ||
562 | * does not return until any executing interrupts for this IRQ | ||
563 | * have completed. | ||
564 | * | ||
565 | * This function must not be called from interrupt context. | ||
566 | */ | 559 | */ |
567 | void free_irq(unsigned int irq, void *dev_id) | 560 | |
561 | struct irqaction *remove_irq(unsigned int irq, void *dev_id) | ||
568 | { | 562 | { |
569 | struct irq_desc *desc = irq_to_desc(irq); | 563 | struct irq_desc *desc = irq_to_desc(irq); |
570 | struct irqaction *action, **action_ptr; | 564 | struct irqaction *action, **action_ptr; |
@@ -573,7 +567,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
573 | WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); | 567 | WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); |
574 | 568 | ||
575 | if (!desc) | 569 | if (!desc) |
576 | return; | 570 | return NULL; |
577 | 571 | ||
578 | spin_lock_irqsave(&desc->lock, flags); | 572 | spin_lock_irqsave(&desc->lock, flags); |
579 | 573 | ||
@@ -589,7 +583,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
589 | WARN(1, "Trying to free already-free IRQ %d\n", irq); | 583 | WARN(1, "Trying to free already-free IRQ %d\n", irq); |
590 | spin_unlock_irqrestore(&desc->lock, flags); | 584 | spin_unlock_irqrestore(&desc->lock, flags); |
591 | 585 | ||
592 | return; | 586 | return NULL; |
593 | } | 587 | } |
594 | 588 | ||
595 | if (action->dev_id == dev_id) | 589 | if (action->dev_id == dev_id) |
@@ -636,7 +630,26 @@ void free_irq(unsigned int irq, void *dev_id) | |||
636 | local_irq_restore(flags); | 630 | local_irq_restore(flags); |
637 | } | 631 | } |
638 | #endif | 632 | #endif |
639 | kfree(action); | 633 | return action; |
634 | } | ||
635 | |||
636 | /** | ||
637 | * free_irq - free an interrupt allocated with request_irq | ||
638 | * @irq: Interrupt line to free | ||
639 | * @dev_id: Device identity to free | ||
640 | * | ||
641 | * Remove an interrupt handler. The handler is removed and if the | ||
642 | * interrupt line is no longer in use by any driver it is disabled. | ||
643 | * On a shared IRQ the caller must ensure the interrupt is disabled | ||
644 | * on the card it drives before calling this function. The function | ||
645 | * does not return until any executing interrupts for this IRQ | ||
646 | * have completed. | ||
647 | * | ||
648 | * This function must not be called from interrupt context. | ||
649 | */ | ||
650 | void free_irq(unsigned int irq, void *dev_id) | ||
651 | { | ||
652 | kfree(remove_irq(irq, dev_id)); | ||
640 | } | 653 | } |
641 | EXPORT_SYMBOL(free_irq); | 654 | EXPORT_SYMBOL(free_irq); |
642 | 655 | ||