1: /* This file contains routines for initializing the 8259 interrupt controller: 2: * put_irq_handler: register an interrupt handler 3: * intr_handle: handle a hardware interrupt 4: * intr_init: initialize the interrupt controller(s) 5: */ 6: 7: #include "kernel.h" 8: 9: #define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */ 10: #define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */ 11: #define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */ 12: #define ICW4_AT 0x01 /* not SFNM, not buffered, normal EOI, 8086 */ 13: #define ICW4_PC 0x09 /* not SFNM, buffered, normal EOI, 8086 */ 14: 15: #if _WORD_SIZE == 2 16: typedef _PROTOTYPE( void (*vecaddr_t), (void) ); 17: 18: FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) ); 19: 20: PRIVATE vecaddr_t int_vec[] = { 21: int00, int01, int02, int03, int04, int05, int06, int07, 22: }; 23: 24: PRIVATE vecaddr_t irq_vec[] = { 25: hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07, 26: hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15, 27: }; 28: #else 29: #define set_vec(nr, addr) ((void)0) 30: #endif 31: 32: 33: /*==========================================================================* 34: * intr_init * 35: *==========================================================================*/ 36: PUBLIC void intr_init(mine) 37: int mine; 38: { 39: /* Initialize the 8259s, finishing with all interrupts disabled. This is 40: * only done in protected mode, in real mode we don't touch the 8259s, but 41: * use the BIOS locations instead. The flag "mine" is set if the 8259s are 42: * to be programmed for Minix, or to be reset to what the BIOS expects. 43: */ 44: 45: int i; 46: 47: lock(); 48: if (protected_mode) { 49: /* The AT and newer PS/2 have two interrupt controllers, one master, 50: * one slaved at IRQ 2. (We don't have to deal with the PC that 51: * has just one controller, because it must run in real mode.) 52: */ 53: outb(INT_CTL, ps_mca ? ICW1_PS : ICW1_AT); 54: outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC); 55: /* ICW2 for master */ 56: outb(INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */ 57: outb(INT_CTLMASK, ICW4_AT); 58: outb(INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */ 59: outb(INT2_CTL, ps_mca ? ICW1_PS : ICW1_AT); 60: outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC); 61: /* ICW2 for slave */ 62: outb(INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */ 63: outb(INT2_CTLMASK, ICW4_AT); 64: outb(INT2_CTLMASK, ~0); /* IRQ 8-15 mask */ 65: 66: /* Copy the BIOS vectors from the BIOS to the Minix location, so we 67: * can still make BIOS calls without reprogramming the i8259s. 68: */ 69: #if IRQ0_VECTOR != BIOS_IRQ0_VEC 70: phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L); 71: #endif 72: #if IRQ8_VECTOR != BIOS_IRQ8_VEC 73: phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L); 74: #endif 75: } else { 76: /* Use the BIOS interrupt vectors in real mode. We only reprogram the 77: * exceptions here, the interrupt vectors are reprogrammed on demand. 78: * SYS_VECTOR is the Minix system call for message passing. 79: */ 80: for (i = 0; i < 8; i++) set_vec(i, int_vec[i]); 81: set_vec(SYS_VECTOR, s_call); 82: } 83: } 84: 85: /*=========================================================================* 86: * put_irq_handler * 87: *=========================================================================*/ 88: PUBLIC void put_irq_handler(hook, irq, handler) 89: irq_hook_t *hook; 90: int irq; 91: irq_handler_t handler; 92: { 93: /* Register an interrupt handler. */ 94: int id; 95: irq_hook_t **line; 96: 97: if ((unsigned) irq >= NR_IRQ_VECTORS) 98: panic("invalid call to put_irq_handler", irq); 99: 100: line = &irq_hooks[irq]; 101: id = 1; 102: while (*line != NULL) { 103: if (hook == *line) return; /* extra initialization */ 104: line = &(*line)->next; 105: id <<= 1; 106: } 107: if (id == 0) panic("Too many handlers for irq", irq); 108: 109: hook->next = NULL; 110: hook->handler = handler; 111: hook->irq = irq; 112: hook->id = id; 113: *line = hook; 114: 115: irq_use |= 1 << irq; 116: } 117: 118: /*==========================================================================* 119: * intr_handle * 120: *==========================================================================*/ 121: PUBLIC void intr_handle(hook) 122: irq_hook_t *hook; 123: { 124: /* Call the interrupt handlers for an interrupt with the given hook list. 125: * The assembly part of the handler has already masked the IRQ, reenabled the 126: * controller(s) and enabled interrupts. 127: */ 128: 129: /* Call list of handlers for an IRQ. */ 130: while (hook != NULL) { 131: /* For each handler in the list, mark it active by setting its ID bit, 132: * call the function, and unmark it if the function returns true. 133: */ 134: irq_actids[hook->irq] |= hook->id; 135: if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id; 136: hook = hook->next; 137: } 138: 139: /* The assembly code will now disable interrupts, unmask the IRQ if and only 140: * if all active ID bits are cleared, and restart a process. 141: */ 142: } 143: 144: #if _WORD_SIZE == 2 145: /*===========================================================================* 146: * set_vec * 147: *===========================================================================*/ 148: PRIVATE void set_vec(vec_nr, addr) 149: int vec_nr; /* which vector */ 150: vecaddr_t addr; /* where to start */ 151: { 152: /* Set up a real mode interrupt vector. */ 153: 154: u16_t vec[2]; 155: 156: /* Build the vector in the array 'vec'. */ 157: vec[0] = (u16_t) addr; 158: vec[1] = (u16_t) physb_to_hclick(code_base); 159: 160: /* Copy the vector into place. */ 161: phys_copy(vir2phys(vec), vec_nr * 4L, 4L); 162: } 163: #endif /* _WORD_SIZE == 2 */