|
|
1.1 root 1: /*
2: * Linux IRQ management.
3: * Copyright (C) 1995 Shantanu Goel.
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2, or (at your option)
8: * any later version.
9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU General Public License for more details.
14: *
15: * You should have received a copy of the GNU General Public License
16: * along with this program; if not, write to the Free Software
17: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18: */
19:
20: /*
21: * linux/arch/i386/kernel/irq.c
22: *
23: * Copyright (C) 1992 Linus Torvalds
24: */
25:
26: #include <sys/types.h>
27:
28: #include <kern/assert.h>
29:
30: #include <i386/machspl.h>
31: #include <i386/ipl.h>
32: #include <i386/pic.h>
33:
34: #define MACH_INCLUDE
35: #include <linux/sched.h>
36: #include <linux/interrupt.h>
37: #include <linux/ptrace.h>
38: #include <linux/errno.h>
39: #include <linux/delay.h>
40: #include <linux/kernel_stat.h>
41:
42: #include <asm/system.h>
43: #include <asm/bitops.h>
44: #include <asm/irq.h>
45:
46: /*
47: * Priority at which a Linux handler should be called.
48: * This is used at the time of an IRQ allocation. It is
49: * set by emulation routines for each class of device.
50: */
51: spl_t linux_intr_pri;
52:
53: /*
54: * Flag indicating an interrupt is being handled.
55: */
56: unsigned long intr_count = 0;
57:
58: /*
59: * List of Linux interrupt handlers.
60: */
61: static void (*linux_handlers[16])(int, struct pt_regs *);
62:
63: extern spl_t curr_ipl;
64: extern int curr_pic_mask;
65: extern int pic_mask[];
66:
67: extern int intnull(), prtnull();
68:
69: /*
70: * Generic interrupt handler for Linux devices.
71: * Set up a fake `struct pt_regs' then call the real handler.
72: */
73: static int
74: linux_intr(irq)
75: int irq;
76: {
77: struct pt_regs regs;
78:
79: kstat.interrupts[irq]++;
80: intr_count++;
81: (*linux_handlers[irq])(irq, ®s);
82: intr_count--;
83: }
84:
85: /*
86: * Mask an IRQ.
87: */
88: void
89: disable_irq(irq)
90: unsigned int irq;
91: {
92: int i, flags;
93:
94: assert (irq < NR_IRQS);
95:
96: save_flags(flags);
97: cli();
98: for (i = 0; i < intpri[irq]; i++)
99: pic_mask[i] |= 1 << irq;
100: if (curr_pic_mask != pic_mask[curr_ipl]) {
101: curr_pic_mask = pic_mask[curr_ipl];
102: outb(PIC_MASTER_OCW, curr_pic_mask);
103: outb(PIC_SLAVE_OCW, curr_pic_mask >> 8);
104: }
105: restore_flags(flags);
106: }
107:
108: /*
109: * Unmask an IRQ.
110: */
111: void
112: enable_irq(irq)
113: unsigned int irq;
114: {
115: int mask, i, flags;
116:
117: assert (irq < NR_IRQS);
118:
119: mask = 1 << irq;
120: if (irq >= 8)
121: mask |= 1 << 2;
122: save_flags(flags);
123: cli();
124: for (i = 0; i < intpri[irq]; i++)
125: pic_mask[i] &= ~mask;
126: if (curr_pic_mask != pic_mask[curr_ipl]) {
127: curr_pic_mask = pic_mask[curr_ipl];
128: outb(PIC_MASTER_OCW, curr_pic_mask);
129: outb(PIC_SLAVE_OCW, curr_pic_mask >> 8);
130: }
131: restore_flags(flags);
132: }
133:
134: /*
135: * Attach a handler to an IRQ.
136: */
137: int
138: request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
139: unsigned long flags, const char *device)
140: {
141: assert(irq < 16);
142:
143: if (ivect[irq] == intnull || ivect[irq] == prtnull) {
144: if (!handler)
145: return (-LINUX_EINVAL);
146: linux_handlers[irq] = handler;
147: ivect[irq] = linux_intr;
148: iunit[irq] = irq;
149: intpri[irq] = linux_intr_pri;
150: enable_irq(irq);
151: return (0);
152: }
153: return (-LINUX_EBUSY);
154: }
155:
156: /*
157: * Deallocate an irq.
158: */
159: void
160: free_irq(unsigned int irq)
161: {
162: if (irq > 15)
163: panic("free_irq: bad irq number");
164:
165: disable_irq(irq);
166: ivect[irq] = (irq == 7) ? prtnull : intnull;
167: iunit[irq] = irq;
168: intpri[irq] = SPL0;
169: }
170:
171: /*
172: * IRQ probe interrupt handler.
173: */
174: void
175: probe_intr(irq)
176: int irq;
177: {
178: disable_irq(irq);
179: }
180:
181: /*
182: * Set for an irq probe.
183: */
184: unsigned long
185: probe_irq_on()
186: {
187: unsigned i, irqs = 0;
188: unsigned long delay;
189:
190: assert (curr_ipl == 0);
191:
192: /*
193: * Allocate all available IRQs.
194: */
195: for (i = 15; i > 0; i--)
196: if (request_irq(i, probe_intr, 0, "probe") == 0)
197: irqs |= 1 << i;
198:
199: /*
200: * Wait for spurious interrupts to mask themselves out.
201: */
202: for (delay = jiffies + 2; delay > jiffies; )
203: ;
204:
205: /*
206: * Free IRQs that caused spurious interrupts.
207: */
208: for (i = 15; i > 0; i--) {
209: if (irqs & (1 << i) & pic_mask[0]) {
210: irqs ^= 1 << i;
211: free_irq(i);
212: }
213: }
214:
215: return (irqs);
216: }
217:
218: /*
219: * Return the result of an irq probe.
220: */
221: int
222: probe_irq_off(unsigned long irqs)
223: {
224: unsigned i, irqs_save = irqs;
225:
226: assert (curr_ipl == 0);
227:
228: irqs &= pic_mask[0];
229:
230: /*
231: * Deallocate IRQs.
232: */
233: for (i = 15; i > 0; i--)
234: if (irqs_save & (1 << i))
235: free_irq(i);
236:
237: /*
238: * Return IRQ number.
239: */
240: if (!irqs)
241: return (0);
242: i = ffz(~irqs);
243: if (irqs != (irqs & (1 << i)))
244: i = -i;
245: return (i);
246: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.