/*1* linux/kernel/irq/autoprobe.c2*3* Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar4*5* This file contains the interrupt probing code and driver APIs.6*/78#include <linux/irq.h>9#include <linux/module.h>10#include <linux/interrupt.h>11#include <linux/delay.h>12#include <linux/async.h>1314#include "internals.h"1516/*17* Autodetection depends on the fact that any interrupt that18* comes in on to an unassigned handler will get stuck with19* "IRQS_WAITING" cleared and the interrupt disabled.20*/21static DEFINE_MUTEX(probing_active);2223/**24* probe_irq_on - begin an interrupt autodetect25*26* Commence probing for an interrupt. The interrupts are scanned27* and a mask of potential interrupt lines is returned.28*29*/30unsigned long probe_irq_on(void)31{32struct irq_desc *desc;33unsigned long mask = 0;34int i;3536/*37* quiesce the kernel, or at least the asynchronous portion38*/39async_synchronize_full();40mutex_lock(&probing_active);41/*42* something may have generated an irq long ago and we want to43* flush such a longstanding irq before considering it as spurious.44*/45for_each_irq_desc_reverse(i, desc) {46raw_spin_lock_irq(&desc->lock);47if (!desc->action && irq_settings_can_probe(desc)) {48/*49* Some chips need to know about probing in50* progress:51*/52if (desc->irq_data.chip->irq_set_type)53desc->irq_data.chip->irq_set_type(&desc->irq_data,54IRQ_TYPE_PROBE);55irq_startup(desc);56}57raw_spin_unlock_irq(&desc->lock);58}5960/* Wait for longstanding interrupts to trigger. */61msleep(20);6263/*64* enable any unassigned irqs65* (we must startup again here because if a longstanding irq66* happened in the previous stage, it may have masked itself)67*/68for_each_irq_desc_reverse(i, desc) {69raw_spin_lock_irq(&desc->lock);70if (!desc->action && irq_settings_can_probe(desc)) {71desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;72if (irq_startup(desc))73desc->istate |= IRQS_PENDING;74}75raw_spin_unlock_irq(&desc->lock);76}7778/*79* Wait for spurious interrupts to trigger80*/81msleep(100);8283/*84* Now filter out any obviously spurious interrupts85*/86for_each_irq_desc(i, desc) {87raw_spin_lock_irq(&desc->lock);8889if (desc->istate & IRQS_AUTODETECT) {90/* It triggered already - consider it spurious. */91if (!(desc->istate & IRQS_WAITING)) {92desc->istate &= ~IRQS_AUTODETECT;93irq_shutdown(desc);94} else95if (i < 32)96mask |= 1 << i;97}98raw_spin_unlock_irq(&desc->lock);99}100101return mask;102}103EXPORT_SYMBOL(probe_irq_on);104105/**106* probe_irq_mask - scan a bitmap of interrupt lines107* @val: mask of interrupts to consider108*109* Scan the interrupt lines and return a bitmap of active110* autodetect interrupts. The interrupt probe logic state111* is then returned to its previous value.112*113* Note: we need to scan all the irq's even though we will114* only return autodetect irq numbers - just so that we reset115* them all to a known state.116*/117unsigned int probe_irq_mask(unsigned long val)118{119unsigned int mask = 0;120struct irq_desc *desc;121int i;122123for_each_irq_desc(i, desc) {124raw_spin_lock_irq(&desc->lock);125if (desc->istate & IRQS_AUTODETECT) {126if (i < 16 && !(desc->istate & IRQS_WAITING))127mask |= 1 << i;128129desc->istate &= ~IRQS_AUTODETECT;130irq_shutdown(desc);131}132raw_spin_unlock_irq(&desc->lock);133}134mutex_unlock(&probing_active);135136return mask & val;137}138EXPORT_SYMBOL(probe_irq_mask);139140/**141* probe_irq_off - end an interrupt autodetect142* @val: mask of potential interrupts (unused)143*144* Scans the unused interrupt lines and returns the line which145* appears to have triggered the interrupt. If no interrupt was146* found then zero is returned. If more than one interrupt is147* found then minus the first candidate is returned to indicate148* their is doubt.149*150* The interrupt probe logic state is returned to its previous151* value.152*153* BUGS: When used in a module (which arguably shouldn't happen)154* nothing prevents two IRQ probe callers from overlapping. The155* results of this are non-optimal.156*/157int probe_irq_off(unsigned long val)158{159int i, irq_found = 0, nr_of_irqs = 0;160struct irq_desc *desc;161162for_each_irq_desc(i, desc) {163raw_spin_lock_irq(&desc->lock);164165if (desc->istate & IRQS_AUTODETECT) {166if (!(desc->istate & IRQS_WAITING)) {167if (!nr_of_irqs)168irq_found = i;169nr_of_irqs++;170}171desc->istate &= ~IRQS_AUTODETECT;172irq_shutdown(desc);173}174raw_spin_unlock_irq(&desc->lock);175}176mutex_unlock(&probing_active);177178if (nr_of_irqs > 1)179irq_found = -irq_found;180181return irq_found;182}183EXPORT_SYMBOL(probe_irq_off);184185186187