3.1.7 branch.
[minix.git] / kernel / interrupt.c
blob61a4a6c17655d6675edb1ba2952c6d3159f5f42b
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 occures.
12 * enable_irq: enable hook for IRQ.
13 * disable_irq: disable hook for IRQ.
16 #include <assert.h>
18 #include "kernel.h"
19 #include "proc.h"
20 #include "archconst.h"
21 #include "hw_intr.h"
23 /* number of lists of IRQ hooks, one list per supported line. */
24 PRIVATE irq_hook_t* irq_handlers[NR_IRQ_VECTORS] = {0};
26 /*===========================================================================*
27 * put_irq_handler *
28 *===========================================================================*/
29 /* Register an interrupt handler. */
30 PUBLIC void put_irq_handler( irq_hook_t* hook, int irq,
31 const irq_handler_t handler)
33 int id;
34 irq_hook_t **line;
35 unsigned long bitmap;
37 if( irq < 0 || irq >= NR_IRQ_VECTORS )
38 panic("invalid call to put_irq_handler: %d", irq);
40 line = &irq_handlers[irq];
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;
49 /* find the lowest id not in use */
50 for (id = 1; id != 0; id <<= 1)
51 if (!(bitmap & id)) break;
53 if(id == 0)
54 panic("Too many handlers for irq: %d", irq);
56 hook->next = NULL;
57 hook->handler = handler;
58 hook->irq = irq;
59 hook->id = id;
60 *line = hook;
61 irq_use |= 1 << irq; /* this does not work for irq >= 32 */
63 /* And as last enable the irq at the hardware.
65 * Internal this activates the line or source of the given interrupt.
67 if((irq_actids[hook->irq] &= ~hook->id) == 0) {
68 hw_intr_unmask(hook->irq);
72 /*===========================================================================*
73 * rm_irq_handler *
74 *===========================================================================*/
75 /* Unregister an interrupt handler. */
76 PUBLIC 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;
81 if( irq < 0 || irq >= NR_IRQ_VECTORS )
82 panic("invalid call to rm_irq_handler: %d", irq);
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_handlers[irq])
90 irq_use &= ~(1 << irq);
91 if (irq_actids[irq] & id)
92 irq_actids[irq] &= ~id;
94 else {
95 line = &(*line)->next;
99 /* Disable the irq if there are no other handlers registered.
100 * If the irq is shared, reenable it if there is no active handler.
102 if (irq_handlers[irq] == NULL) {
103 hw_intr_mask(irq);
105 else if (irq_actids[irq] == 0) {
106 hw_intr_unmask(irq);
110 /*===========================================================================*
111 * irq_handle *
112 *===========================================================================*/
114 * The function first disables interrupt is need be and restores the state at
115 * the end. Before returning, it unmasks the IRQ if and only if all active ID
116 * bits are cleared, and restart a process.
118 PUBLIC void irq_handle(int irq)
120 irq_hook_t * hook;
122 /* here we need not to get this IRQ until all the handlers had a say */
123 assert(irq >= 0 && irq < NR_IRQ_VECTORS);
124 hw_intr_mask(irq);
125 hook = irq_handlers[irq];
127 /* Check for spurious interrupts. */
128 if(hook == NULL) {
129 static int nspurious[NR_IRQ_VECTORS], report_interval = 100;
130 nspurious[irq]++;
131 if(nspurious[irq] == 1 || !(nspurious[irq] % report_interval)) {
132 printf("irq_handle: spurious irq %d (count: %d); keeping masked\n",
133 irq, nspurious[irq]);
134 if(report_interval < INT_MAX/2)
135 report_interval *= 2;
137 return;
140 /* Call list of handlers for an IRQ. */
141 while( hook != NULL ) {
142 /* For each handler in the list, mark it active by setting its ID bit,
143 * call the function, and unmark it if the function returns true.
145 irq_actids[irq] |= hook->id;
147 /* Call the hooked function. */
148 if( (*hook->handler)(hook) )
149 irq_actids[hook->irq] &= ~hook->id;
151 /* Next hooked function. */
152 hook = hook->next;
155 /* reenable the IRQ only if there is no active handler */
156 if (irq_actids[irq] == 0)
157 hw_intr_unmask(irq);
160 /* Enable/Disable a interrupt line. */
161 PUBLIC void enable_irq(const irq_hook_t *hook)
163 if((irq_actids[hook->irq] &= ~hook->id) == 0) {
164 hw_intr_unmask(hook->irq);
168 /* Return true if the interrupt was enabled before call. */
169 PUBLIC int disable_irq(const irq_hook_t *hook)
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;