|
|
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: #include <mach/mach_types.h>
28: #include <mach/vm_param.h>
29: #include <kern/assert.h>
30:
31: #include <i386/spl.h>
32: #include <i386/pic.h>
33: #include <i386/pit.h>
34:
35: #define MACH_INCLUDE
36: #include <linux/mm.h>
37: #include <linux/interrupt.h>
38: #include <linux/ptrace.h>
39: #include <linux/delay.h>
40: #include <linux/kernel_stat.h>
41: #include <linux/malloc.h>
42: #include <linux/ioport.h>
43:
44: #include <asm/system.h>
45: #include <asm/bitops.h>
46: #include <asm/irq.h>
47: #include <asm/io.h>
48:
49: extern int linux_timer_intr (void);
50: extern spl_t splhigh (void);
51: extern spl_t spl0 (void);
52: extern void form_pic_mask (void);
53:
54: /*
55: * XXX Move this into more suitable place...
56: * Set if the machine has an EISA bus.
57: */
58: int EISA_bus = 0;
59:
60: /*
61: * Priority at which a Linux handler should be called.
62: * This is used at the time of an IRQ allocation. It is
63: * set by emulation routines for each class of device.
64: */
65: spl_t linux_intr_pri;
66:
67: /*
68: * Flag indicating an interrupt is being handled.
69: */
70: unsigned long intr_count = 0;
71:
72: /*
73: * List of Linux interrupt handlers.
74: */
75: struct linux_action
76: {
77: void (*handler) (int, void *, struct pt_regs *);
78: void *dev_id;
79: struct linux_action *next;
80: unsigned long flags;
81: };
82:
83: static struct linux_action *irq_action[16] =
84: {
85: NULL, NULL, NULL, NULL,
86: NULL, NULL, NULL, NULL,
87: NULL, NULL, NULL, NULL,
88: NULL, NULL, NULL, NULL
89: };
90:
91: extern spl_t curr_ipl;
92: extern int curr_pic_mask;
93: extern int pic_mask[];
94:
95: extern int intnull (), prtnull ();
96:
97: /*
98: * Generic interrupt handler for Linux devices.
99: * Set up a fake `struct pt_regs' then call the real handler.
100: */
101: static int
102: linux_intr (int irq)
103: {
104: struct pt_regs regs;
105: struct linux_action *action = *(irq_action + irq);
106:
107: kstat.interrupts[irq]++;
108: intr_count++;
109:
110: while (action)
111: {
112: action->handler (irq, action->dev_id, ®s);
113: action = action->next;
114: }
115:
116: intr_count--;
117:
118: /* Not used. by OKUJI Yoshinori. */
119: return 0;
120: }
121:
122: /*
123: * Mask an IRQ.
124: */
125: static inline void
126: mask_irq (unsigned int irq_nr)
127: {
128: int i;
129:
130: for (i = 0; i < intpri[irq_nr]; i++)
131: pic_mask[i] |= 1 << irq_nr;
132:
133: if (curr_pic_mask != pic_mask[curr_ipl])
134: {
135: curr_pic_mask = pic_mask[curr_ipl];
136: if (irq_nr < 8)
137: outb (curr_pic_mask & 0xff, PIC_MASTER_OCW);
138: else
139: outb (curr_pic_mask >> 8, PIC_SLAVE_OCW);
140: }
141: }
142:
143: /*
144: * Unmask an IRQ.
145: */
146: static inline void
147: unmask_irq (unsigned int irq_nr)
148: {
149: int mask, i;
150:
151: mask = 1 << irq_nr;
152: if (irq_nr >= 8)
153: mask |= 1 << 2;
154:
155: for (i = 0; i < intpri[irq_nr]; i++)
156: pic_mask[i] &= ~mask;
157:
158: if (curr_pic_mask != pic_mask[curr_ipl])
159: {
160: curr_pic_mask = pic_mask[curr_ipl];
161: if (irq_nr < 8)
162: outb (curr_pic_mask & 0xff, PIC_MASTER_OCW);
163: else
164: outb (curr_pic_mask >> 8, PIC_SLAVE_OCW);
165: }
166: }
167:
168: void
169: disable_irq (unsigned int irq_nr)
170: {
171: unsigned long flags;
172:
173: assert (irq_nr < NR_IRQS);
174:
175: save_flags (flags);
176: cli ();
177: mask_irq (irq_nr);
178: restore_flags (flags);
179: }
180:
181: void
182: enable_irq (unsigned int irq_nr)
183: {
184: unsigned long flags;
185:
186: assert (irq_nr < NR_IRQS);
187:
188: save_flags (flags);
189: cli ();
190: unmask_irq (irq_nr);
191: restore_flags (flags);
192: }
193:
194: /*
195: * Default interrupt handler for Linux.
196: */
197: int
198: linux_bad_intr (int irq)
199: {
200: mask_irq (irq);
201: return 0;
202: }
203:
204: static int
205: setup_x86_irq (int irq, struct linux_action *new)
206: {
207: int shared = 0;
208: struct linux_action *old, **p;
209: unsigned long flags;
210:
211: p = irq_action + irq;
212: if ((old = *p) != NULL)
213: {
214: /* Can't share interrupts unless both agree to */
215: if (!(old->flags & new->flags & SA_SHIRQ))
216: return (-LINUX_EBUSY);
217:
218: /* Can't share interrupts unless both are same type */
219: if ((old->flags ^ new->flags) & SA_INTERRUPT)
220: return (-LINUX_EBUSY);
221:
222: /* add new interrupt at end of irq queue */
223: do
224: {
225: p = &old->next;
226: old = *p;
227: }
228: while (old);
229: shared = 1;
230: }
231:
232: save_flags (flags);
233: cli ();
234: *p = new;
235:
236: if (!shared)
237: {
238: ivect[irq] = linux_intr;
239: iunit[irq] = irq;
240: intpri[irq] = linux_intr_pri;
241: unmask_irq (irq);
242: }
243: restore_flags (flags);
244: return 0;
245: }
246:
247: /*
248: * Attach a handler to an IRQ.
249: */
250: int
251: request_irq (unsigned int irq, void (*handler) (int, void *, struct pt_regs *),
252: unsigned long flags, const char *device, void *dev_id)
253: {
254: struct linux_action *action;
255: int retval;
256:
257: assert (irq < 16);
258:
259: if (!handler)
260: return -LINUX_EINVAL;
261:
262: /*
263: * Hmm... Should I use `kalloc()' ?
264: * By OKUJI Yoshinori.
265: */
266: action = (struct linux_action *)
267: linux_kmalloc (sizeof (struct linux_action), GFP_KERNEL);
268: if (action == NULL)
269: return -LINUX_ENOMEM;
270:
271: action->handler = handler;
272: action->next = NULL;
273: action->dev_id = dev_id;
274: action->flags = flags;
275:
276: retval = setup_x86_irq (irq, action);
277: if (retval)
278: linux_kfree (action);
279:
280: return retval;
281: }
282:
283: /*
284: * Deallocate an irq.
285: */
286: void
287: free_irq (unsigned int irq, void *dev_id)
288: {
289: struct linux_action *action, **p;
290: unsigned long flags;
291:
292: if (irq > 15)
293: panic ("free_irq: bad irq number");
294:
295: for (p = irq_action + irq; (action = *p) != NULL; p = &action->next)
296: {
297: if (action->dev_id != dev_id)
298: continue;
299:
300: save_flags (flags);
301: cli ();
302: *p = action->next;
303: if (!irq_action[irq])
304: {
305: mask_irq (irq);
306: ivect[irq] = linux_bad_intr;
307: iunit[irq] = irq;
308: intpri[irq] = SPL0;
309: }
310: restore_flags (flags);
311: linux_kfree (action);
312: return;
313: }
314:
315: panic ("free_irq: bad irq number");
316: }
317:
318: /*
319: * Set for an irq probe.
320: */
321: unsigned long
322: probe_irq_on (void)
323: {
324: unsigned i, irqs = 0;
325: unsigned long delay;
326:
327: assert (curr_ipl == 0);
328:
329: /*
330: * Allocate all available IRQs.
331: */
332: for (i = 15; i > 0; i--)
333: {
334: if (!irq_action[i] && ivect[i] == linux_bad_intr)
335: {
336: intpri[i] = linux_intr_pri;
337: enable_irq (i);
338: irqs |= 1 << i;
339: }
340: }
341:
342: /*
343: * Wait for spurious interrupts to mask themselves out.
344: */
345: for (delay = jiffies + HZ / 10; delay > jiffies;)
346: ;
347:
348: return (irqs & ~curr_pic_mask);
349: }
350:
351: /*
352: * Return the result of an irq probe.
353: */
354: int
355: probe_irq_off (unsigned long irqs)
356: {
357: unsigned int i;
358:
359: assert (curr_ipl == 0);
360:
361: irqs &= curr_pic_mask;
362:
363: /*
364: * Disable unnecessary IRQs.
365: */
366: for (i = 15; i > 0; i--)
367: {
368: if (!irq_action[i] && ivect[i] == linux_bad_intr)
369: {
370: disable_irq (i);
371: intpri[i] = SPL0;
372: }
373: }
374:
375: /*
376: * Return IRQ number.
377: */
378: if (!irqs)
379: return 0;
380: i = ffz (~irqs);
381: if (irqs != (irqs & (1 << i)))
382: i = -i;
383: return i;
384: }
385:
386: /*
387: * Reserve IRQs used by Mach drivers.
388: * Must be called before Linux IRQ detection, after Mach IRQ detection.
389: */
390: static void
391: reserve_mach_irqs (void)
392: {
393: unsigned int i;
394:
395: for (i = 0; i < 16; i++)
396: {
397: if (ivect[i] != prtnull && ivect[i] != intnull)
398: /* Set non-NULL value. */
399: irq_action[i] = (struct linux_action *) -1;
400: }
401: }
402:
403: static int (*old_clock_handler) ();
404: static int old_clock_pri;
405:
406: void
407: init_IRQ (void)
408: {
409: int i;
410: char *p;
411: int latch = (CLKNUM + hz / 2) / hz;
412:
413: /*
414: * Ensure interrupts are disabled.
415: */
416: (void) splhigh ();
417:
418: /*
419: * Program counter 0 of 8253 to interrupt hz times per second.
420: */
421: outb_p (PIT_C0 | PIT_SQUAREMODE | PIT_READMODE, PITCTL_PORT);
422: outb_p (latch && 0xff, PITCTR0_PORT);
423: outb (latch >> 8, PITCTR0_PORT);
424:
425: /*
426: * Install our clock interrupt handler.
427: */
428: old_clock_handler = ivect[0];
429: old_clock_pri = intpri[0];
430: ivect[0] = linux_timer_intr;
431: intpri[0] = SPLHI;
432:
433: reserve_mach_irqs ();
434:
435: for (i = 1; i < 16; i++)
436: {
437: /*
438: * irq2 and irq13 should be igonored.
439: */
440: if (i == 2 || i == 13)
441: continue;
442: if (ivect[i] == prtnull || ivect[i] == intnull)
443: {
444: ivect[i] = linux_bad_intr;
445: iunit[i] = i;
446: intpri[i] = SPL0;
447: }
448: }
449:
450: form_pic_mask ();
451:
452: /*
453: * Enable interrupts.
454: */
455: (void) spl0 ();
456:
457: /*
458: * Check if the machine has an EISA bus.
459: */
460: p = (char *) 0x0FFFD9;
461: if (*p++ == 'E' && *p++ == 'I' && *p++ == 'S' && *p == 'A')
462: EISA_bus = 1;
463:
464: /*
465: * Permanently allocate standard device ports.
466: */
467: request_region (0x00, 0x20, "dma1");
468: request_region (0x20, 0x20, "pic1");
469: request_region (0x40, 0x20, "timer");
470: request_region (0x70, 0x10, "rtc");
471: request_region (0x80, 0x20, "dma page reg");
472: request_region (0xa0, 0x20, "pic2");
473: request_region (0xc0, 0x20, "dma2");
474: request_region (0xf0, 0x10, "npu");
475: }
476:
477: void
478: restore_IRQ (void)
479: {
480: /*
481: * Disable interrupts.
482: */
483: (void) splhigh ();
484:
485: /*
486: * Restore clock interrupt handler.
487: */
488: ivect[0] = old_clock_handler;
489: intpri[0] = old_clock_pri;
490: form_pic_mask ();
491: }
492:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.