|
|
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.