[PATCH] genirq: core
[safe/jmp/linux-2.6] / kernel / irq / autoprobe.c
1 /*
2  * linux/kernel/irq/autoprobe.c
3  *
4  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5  *
6  * This file contains the interrupt probing code and driver APIs.
7  */
8
9 #include <linux/irq.h>
10 #include <linux/module.h>
11 #include <linux/interrupt.h>
12 #include <linux/delay.h>
13
14 /*
15  * Autodetection depends on the fact that any interrupt that
16  * comes in on to an unassigned handler will get stuck with
17  * "IRQ_WAITING" cleared and the interrupt disabled.
18  */
19 static DEFINE_MUTEX(probing_active);
20
21 /**
22  *      probe_irq_on    - begin an interrupt autodetect
23  *
24  *      Commence probing for an interrupt. The interrupts are scanned
25  *      and a mask of potential interrupt lines is returned.
26  *
27  */
28 unsigned long probe_irq_on(void)
29 {
30         struct irq_desc *desc;
31         unsigned long mask;
32         unsigned int i;
33
34         mutex_lock(&probing_active);
35         /*
36          * something may have generated an irq long ago and we want to
37          * flush such a longstanding irq before considering it as spurious.
38          */
39         for (i = NR_IRQS-1; i > 0; i--) {
40                 desc = irq_desc + i;
41
42                 spin_lock_irq(&desc->lock);
43                 if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
44                         /*
45                          * Some chips need to know about probing in
46                          * progress:
47                          */
48                         if (desc->chip->set_type)
49                                 desc->chip->set_type(i, IRQ_TYPE_PROBE);
50                         desc->chip->startup(i);
51                 }
52                 spin_unlock_irq(&desc->lock);
53         }
54
55         /* Wait for longstanding interrupts to trigger. */
56         msleep(20);
57
58         /*
59          * enable any unassigned irqs
60          * (we must startup again here because if a longstanding irq
61          * happened in the previous stage, it may have masked itself)
62          */
63         for (i = NR_IRQS-1; i > 0; i--) {
64                 desc = irq_desc + i;
65
66                 spin_lock_irq(&desc->lock);
67                 if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
68                         desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
69                         if (desc->chip->startup(i))
70                                 desc->status |= IRQ_PENDING;
71                 }
72                 spin_unlock_irq(&desc->lock);
73         }
74
75         /*
76          * Wait for spurious interrupts to trigger
77          */
78         msleep(100);
79
80         /*
81          * Now filter out any obviously spurious interrupts
82          */
83         mask = 0;
84         for (i = 0; i < NR_IRQS; i++) {
85                 unsigned int status;
86
87                 desc = irq_desc + i;
88                 spin_lock_irq(&desc->lock);
89                 status = desc->status;
90
91                 if (status & IRQ_AUTODETECT) {
92                         /* It triggered already - consider it spurious. */
93                         if (!(status & IRQ_WAITING)) {
94                                 desc->status = status & ~IRQ_AUTODETECT;
95                                 desc->chip->shutdown(i);
96                         } else
97                                 if (i < 32)
98                                         mask |= 1 << i;
99                 }
100                 spin_unlock_irq(&desc->lock);
101         }
102
103         return mask;
104 }
105 EXPORT_SYMBOL(probe_irq_on);
106
107 /**
108  *      probe_irq_mask - scan a bitmap of interrupt lines
109  *      @val:   mask of interrupts to consider
110  *
111  *      Scan the interrupt lines and return a bitmap of active
112  *      autodetect interrupts. The interrupt probe logic state
113  *      is then returned to its previous value.
114  *
115  *      Note: we need to scan all the irq's even though we will
116  *      only return autodetect irq numbers - just so that we reset
117  *      them all to a known state.
118  */
119 unsigned int probe_irq_mask(unsigned long val)
120 {
121         unsigned int mask;
122         int i;
123
124         mask = 0;
125         for (i = 0; i < NR_IRQS; i++) {
126                 struct irq_desc *desc = irq_desc + i;
127                 unsigned int status;
128
129                 spin_lock_irq(&desc->lock);
130                 status = desc->status;
131
132                 if (status & IRQ_AUTODETECT) {
133                         if (i < 16 && !(status & IRQ_WAITING))
134                                 mask |= 1 << i;
135
136                         desc->status = status & ~IRQ_AUTODETECT;
137                         desc->chip->shutdown(i);
138                 }
139                 spin_unlock_irq(&desc->lock);
140         }
141         mutex_unlock(&probing_active);
142
143         return mask & val;
144 }
145 EXPORT_SYMBOL(probe_irq_mask);
146
147 /**
148  *      probe_irq_off   - end an interrupt autodetect
149  *      @val: mask of potential interrupts (unused)
150  *
151  *      Scans the unused interrupt lines and returns the line which
152  *      appears to have triggered the interrupt. If no interrupt was
153  *      found then zero is returned. If more than one interrupt is
154  *      found then minus the first candidate is returned to indicate
155  *      their is doubt.
156  *
157  *      The interrupt probe logic state is returned to its previous
158  *      value.
159  *
160  *      BUGS: When used in a module (which arguably shouldn't happen)
161  *      nothing prevents two IRQ probe callers from overlapping. The
162  *      results of this are non-optimal.
163  */
164 int probe_irq_off(unsigned long val)
165 {
166         int i, irq_found = 0, nr_irqs = 0;
167
168         for (i = 0; i < NR_IRQS; i++) {
169                 struct irq_desc *desc = irq_desc + i;
170                 unsigned int status;
171
172                 spin_lock_irq(&desc->lock);
173                 status = desc->status;
174
175                 if (status & IRQ_AUTODETECT) {
176                         if (!(status & IRQ_WAITING)) {
177                                 if (!nr_irqs)
178                                         irq_found = i;
179                                 nr_irqs++;
180                         }
181                         desc->status = status & ~IRQ_AUTODETECT;
182                         desc->chip->shutdown(i);
183                 }
184                 spin_unlock_irq(&desc->lock);
185         }
186         mutex_unlock(&probing_active);
187
188         if (nr_irqs > 1)
189                 irq_found = -irq_found;
190
191         return irq_found;
192 }
193 EXPORT_SYMBOL(probe_irq_off);
194