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