1 /* 2 * The Minix hardware interrupt system. 3 * 4 * This file contains routines for managing the interrupt 5 * controller. 6 * 7 * put_irq_handler: register an interrupt handler. 8 * rm_irq_handler: deregister an interrupt handler. 9 * irq_handle: handle a hardware interrupt. 10 * called by the system dependent part when an 11 * external interrupt occurs. 12 * enable_irq: enable hook for IRQ. 13 * disable_irq: disable hook for IRQ. 14 */ 15 16 #include <assert.h> 17 18 #include "kernel/kernel.h" 19 #include "archconst.h" 20 #include "hw_intr.h" 21 22 23 /* number of lists of IRQ hooks, one list per supported line. */ 24 static irq_hook_t* irq_handlers[NR_IRQ_VECTORS] = {0}; 25 26 /*===========================================================================* 27 * put_irq_handler * 28 *===========================================================================*/ 29 /* Register an interrupt handler. */ 30 void put_irq_handler( irq_hook_t* hook, int irq, 31 const irq_handler_t handler) 32 { 33 int id; 34 irq_hook_t **line; 35 unsigned long bitmap; 36 37 if( irq < 0 || irq >= NR_IRQ_VECTORS ) 38 panic("invalid call to put_irq_handler: %d", irq); 39 40 line = &irq_handlers[irq]; 41 42 bitmap = 0; 43 while ( *line != NULL ) { 44 if(hook == *line) return; /* extra initialization */ 45 bitmap |= (*line)->id; /* mark ids in use */ 46 line = &(*line)->next; 47 } 48 49 /* find the lowest id not in use */ 50 for (id = 1; id != 0; id <<= 1) 51 if (!(bitmap & id)) break; 52 53 if(id == 0) 54 panic("Too many handlers for irq: %d", irq); 55 56 hook->next = NULL; 57 hook->handler = handler; 58 hook->irq = irq; 59 hook->id = id; 60 *line = hook; 61 62 /* And as last enable the irq at the hardware. 63 * 64 * Internal this activates the line or source of the given interrupt. 65 */ 66 if((irq_actids[hook->irq] &= ~hook->id) == 0) { 67 hw_intr_used(irq); 68 hw_intr_unmask(hook->irq); 69 } 70 } 71 72 /*===========================================================================* 73 * rm_irq_handler * 74 *===========================================================================*/ 75 /* Unregister an interrupt handler. */ 76 void rm_irq_handler( const irq_hook_t* hook ) { 77 const int irq = hook->irq; 78 const int id = hook->id; 79 irq_hook_t **line; 80 81 if( irq < 0 || irq >= NR_IRQ_VECTORS ) 82 panic("invalid call to rm_irq_handler: %d", irq); 83 84 /* remove the hook */ 85 line = &irq_handlers[irq]; 86 while( (*line) != NULL ) { 87 if((*line)->id == id) { 88 (*line) = (*line)->next; 89 if (irq_actids[irq] & id) 90 irq_actids[irq] &= ~id; 91 } 92 else { 93 line = &(*line)->next; 94 } 95 } 96 97 /* Disable the irq if there are no other handlers registered. 98 * If the irq is shared, reenable it if there is no active handler. 99 */ 100 if (irq_handlers[irq] == NULL) { 101 hw_intr_mask(irq); 102 hw_intr_not_used(irq); 103 } 104 else if (irq_actids[irq] == 0) { 105 hw_intr_unmask(irq); 106 } 107 } 108 109 /*===========================================================================* 110 * irq_handle * 111 *===========================================================================*/ 112 /* 113 * The function first disables interrupt is need be and restores the state at 114 * the end. Before returning, it unmasks the IRQ if and only if all active ID 115 * bits are cleared, and restart a process. 116 */ 117 void irq_handle(int irq) 118 { 119 irq_hook_t * hook; 120 121 /* here we need not to get this IRQ until all the handlers had a say */ 122 assert(irq >= 0 && irq < NR_IRQ_VECTORS); 123 hw_intr_mask(irq); 124 hook = irq_handlers[irq]; 125 126 /* Check for spurious interrupts. */ 127 if(hook == NULL) { 128 static int nspurious[NR_IRQ_VECTORS], report_interval = 100; 129 nspurious[irq]++; 130 if(nspurious[irq] == 1 || !(nspurious[irq] % report_interval)) { 131 printf("irq_handle: spurious irq %d (count: %d); keeping masked\n", 132 irq, nspurious[irq]); 133 if(report_interval < INT_MAX/2) 134 report_interval *= 2; 135 } 136 return; 137 } 138 139 /* Call list of handlers for an IRQ. */ 140 while( hook != NULL ) { 141 /* For each handler in the list, mark it active by setting its ID bit, 142 * call the function, and unmark it if the function returns true. 143 */ 144 irq_actids[irq] |= hook->id; 145 146 /* Call the hooked function. */ 147 if( (*hook->handler)(hook) ) 148 irq_actids[hook->irq] &= ~hook->id; 149 150 /* Next hooked function. */ 151 hook = hook->next; 152 } 153 154 /* reenable the IRQ only if there is no active handler */ 155 if (irq_actids[irq] == 0) 156 hw_intr_unmask(irq); 157 158 hw_intr_ack(irq); 159 } 160 161 /* Enable/Disable a interrupt line. */ 162 void enable_irq(const irq_hook_t *hook) 163 { 164 if((irq_actids[hook->irq] &= ~hook->id) == 0) { 165 hw_intr_unmask(hook->irq); 166 } 167 } 168 169 /* Return true if the interrupt was enabled before call. */ 170 int disable_irq(const irq_hook_t *hook) 171 { 172 if(irq_actids[hook->irq] & hook->id) /* already disabled */ 173 return 0; 174 irq_actids[hook->irq] |= hook->id; 175 hw_intr_mask(hook->irq); 176 return TRUE; 177 } 178 179