2 * The Minix hardware interrupt system.
4 * This file contains routines for managing the interrupt
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.
20 #include "archconst.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 /*===========================================================================*
28 *===========================================================================*/
29 /* Register an interrupt handler. */
30 PUBLIC
void put_irq_handler( irq_hook_t
* hook
, int irq
,
31 const irq_handler_t handler
)
37 if( irq
< 0 || irq
>= NR_IRQ_VECTORS
)
38 panic("invalid call to put_irq_handler: %d", irq
);
40 line
= &irq_handlers
[irq
];
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;
54 panic("Too many handlers for irq: %d", irq
);
57 hook
->handler
= handler
;
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 /*===========================================================================*
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
;
81 if( irq
< 0 || irq
>= NR_IRQ_VECTORS
)
82 panic("invalid call to rm_irq_handler: %d", irq
);
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
;
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
) {
105 else if (irq_actids
[irq
] == 0) {
110 /*===========================================================================*
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
)
122 /* here we need not to get this IRQ until all the handlers had a say */
123 assert(irq
>= 0 && irq
< NR_IRQ_VECTORS
);
125 hook
= irq_handlers
[irq
];
127 /* Check for spurious interrupts. */
129 static int nspurious
[NR_IRQ_VECTORS
], report_interval
= 100;
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;
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. */
155 /* reenable the IRQ only if there is no active handler */
156 if (irq_actids
[irq
] == 0)
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 */
173 irq_actids
[hook
->irq
] |= hook
->id
;
174 hw_intr_mask(hook
->irq
);