]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/irq/manage.c
Fix oops in acer_wmi driver (acer_wmi_init)
[linux-2.6-omap-h63xx.git] / kernel / irq / manage.c
index 3cfc0fefb5ee671e1565862f1b54ee431af4eb8a..0314074fa232e72370db9e62b50cdc98a8d53f6a 100644 (file)
@@ -177,8 +177,7 @@ static void __enable_irq(struct irq_desc *desc, unsigned int irq)
 {
        switch (desc->depth) {
        case 0:
-               printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
-               WARN_ON(1);
+               WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
                break;
        case 1: {
                unsigned int status = desc->status & ~IRQ_DISABLED;
@@ -260,9 +259,7 @@ int set_irq_wake(unsigned int irq, unsigned int on)
                }
        } else {
                if (desc->wake_depth == 0) {
-                       printk(KERN_WARNING "Unbalanced IRQ %d "
-                                       "wake disable\n", irq);
-                       WARN_ON(1);
+                       WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
                } else if (--desc->wake_depth == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)
@@ -308,6 +305,31 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
                desc->handle_irq = NULL;
 }
 
+static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
+               unsigned long flags)
+{
+       int ret;
+
+       if (!chip || !chip->set_type) {
+               /*
+                * IRQF_TRIGGER_* but the PIC does not support multiple
+                * flow-types?
+                */
+               pr_warning("No set_type function for IRQ %d (%s)\n", irq,
+                               chip ? (chip->name ? : "unknown") : "unknown");
+               return 0;
+       }
+
+       ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
+
+       if (ret)
+               pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
+                               (int)(flags & IRQF_TRIGGER_MASK),
+                               irq, chip->set_type);
+
+       return ret;
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -319,6 +341,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        const char *old_name = NULL;
        unsigned long flags;
        int shared = 0;
+       int ret;
 
        if (irq >= NR_IRQS)
                return -EINVAL;
@@ -376,35 +399,23 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                shared = 1;
        }
 
-       *p = new;
-
-       /* Exclude IRQ from balancing */
-       if (new->flags & IRQF_NOBALANCING)
-               desc->status |= IRQ_NO_BALANCING;
-
        if (!shared) {
                irq_chip_set_defaults(desc->chip);
 
-#if defined(CONFIG_IRQ_PER_CPU)
-               if (new->flags & IRQF_PERCPU)
-                       desc->status |= IRQ_PER_CPU;
-#endif
-
                /* Setup the type (level, edge polarity) if configured: */
                if (new->flags & IRQF_TRIGGER_MASK) {
-                       if (desc->chip->set_type)
-                               desc->chip->set_type(irq,
-                                               new->flags & IRQF_TRIGGER_MASK);
-                       else
-                               /*
-                                * IRQF_TRIGGER_* but the PIC does not support
-                                * multiple flow-types?
-                                */
-                               printk(KERN_WARNING "No IRQF_TRIGGER set_type "
-                                      "function for IRQ %d (%s)\n", irq,
-                                      desc->chip->name);
+                       ret = __irq_set_trigger(desc->chip, irq, new->flags);
+
+                       if (ret) {
+                               spin_unlock_irqrestore(&desc->lock, flags);
+                               return ret;
+                       }
                } else
                        compat_irq_chip_set_default_handler(desc);
+#if defined(CONFIG_IRQ_PER_CPU)
+               if (new->flags & IRQF_PERCPU)
+                       desc->status |= IRQ_PER_CPU;
+#endif
 
                desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
                                  IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
@@ -423,6 +434,13 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                /* Set default affinity mask once everything is setup */
                irq_select_affinity(irq);
        }
+
+       *p = new;
+
+       /* Exclude IRQ from balancing */
+       if (new->flags & IRQF_NOBALANCING)
+               desc->status |= IRQ_NO_BALANCING;
+
        /* Reset broken irq detection when installing new handler */
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;