1 /* $Id: irq.c,v 1.15 2000/07/04 08:52:37 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/hal/x86/irq.c
6 * PURPOSE: IRQ handling
7 * PROGRAMMER: David Welch (welch@mcmail.com)
13 * NOTE: In general the PIC interrupt priority facilities are used to
14 * preserve the NT IRQL semantics, global interrupt disables are only used
15 * to keep the PIC in a consistent state
19 /* INCLUDES ****************************************************************/
21 #include <ddk/ntddk.h>
23 #include <internal/stddef.h>
24 #include <internal/ntoskrnl.h>
25 #include <internal/ke.h>
26 #include <internal/bitops.h>
28 #include <internal/string.h>
30 #include <internal/i386/segment.h>
31 #include <internal/halio.h>
32 #include <internal/hal.h>
35 #include <internal/debug.h>
37 /* GLOBALS *****************************************************************/
40 #define IRQ_BASE (0x40)
42 void irq_handler_0(void);
43 void irq_handler_1(void);
44 void irq_handler_2(void);
45 void irq_handler_3(void);
46 void irq_handler_4(void);
47 void irq_handler_5(void);
48 void irq_handler_6(void);
49 void irq_handler_7(void);
50 void irq_handler_8(void);
51 void irq_handler_9(void);
52 void irq_handler_10(void);
53 void irq_handler_11(void);
54 void irq_handler_12(void);
55 void irq_handler_13(void);
56 void irq_handler_14(void);
57 void irq_handler_15(void);
59 static unsigned int irq_handler
[NR_IRQS
]=
80 * PURPOSE: Object describing each isr
81 * NOTE: The data in this table is only modified at passsive level but can
82 * be accessed at any irq level.
84 static LIST_ENTRY isr_table
[NR_IRQS
]={{NULL
,NULL
},};
85 static PKSPIN_LOCK isr_lock
[NR_IRQS
] = {NULL
,};
86 static KSPIN_LOCK isr_table_lock
= {0,};
88 /* FUNCTIONS ****************************************************************/
91 #define PRESENT (0x8000)
92 #define I486_INTERRUPT_GATE (0xe00)
95 VOID
HalpDispatchInterrupt (ULONG irq
)
97 * FUNCTION: Calls the irq specific handler for an irq
99 * irq = IRQ that has interrupted
109 * Notify the rest of the kernel of the raised irq level
111 old_level
= KeGetCurrentIrql();
114 DPRINT("old_level %d\n",old_level
);
116 KeSetCurrentIrql(HIGH_LEVEL
- irq
);
120 * NOTE: Only higher priority interrupts will get through
126 KiUpdateSystemTime();
130 DPRINT("HalpDispatchInterrupt(irq %d)\n",irq
);
131 // KiInterruptDispatch (irq);
133 * Iterate the list until one of the isr tells us its device interrupted
135 current
= isr_table
[irq
].Flink
;
136 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
137 DPRINT("current %x isr %x\n",current
,isr
);
138 while (current
!=(&isr_table
[irq
]) &&
139 !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
141 current
= current
->Flink
;
142 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
143 DPRINT("current %x isr %x\n",current
,isr
);
153 * Send EOI to the PIC
162 * Unmask the related irq
166 outb(0x21,inb(0x21)&(~(1<<irq
)));
170 outb(0xa1,inb(0xa1)&(~(1<<(irq
-8))));
174 * If the processor level will drop below dispatch level on return then
175 * issue a DPC queue drain interrupt
177 if (old_level
< DISPATCH_LEVEL
)
179 KeSetCurrentIrql(DISPATCH_LEVEL
);
181 KiDispatchInterrupt(irq
);
187 KeSetCurrentIrql(old_level
);
191 VOID
HalpInitIRQs (VOID
)
195 DPRINT("HalpInitIRQs ()\n",0);
198 * First mask off all interrupts from pic
205 * Setup the IDT entries to point to the interrupt handlers
207 for (i
=0;i
<NR_IRQS
;i
++)
209 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
210 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
212 InitializeListHead(&isr_table
[i
]);
216 static VOID
KeDumpIrqList(VOID
)
219 PLIST_ENTRY current_entry
;
222 for (i
=0;i
<NR_IRQS
;i
++)
224 DPRINT("For irq %x ",i
);
225 current_entry
= isr_table
[i
].Flink
;
226 current
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
227 while (current_entry
!=(&isr_table
[i
]))
229 DPRINT("Isr %x ",current
);
230 current_entry
= current_entry
->Flink
;
231 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
239 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
240 PKSERVICE_ROUTINE ServiceRoutine
,
241 PVOID ServiceContext
,
242 PKSPIN_LOCK SpinLock
,
245 KIRQL SynchronizeIrql
,
246 KINTERRUPT_MODE InterruptMode
,
248 KAFFINITY ProcessorEnableMask
,
249 BOOLEAN FloatingSave
)
251 * FUNCTION: Registers a driver's isr to be called when its device interrupts
253 * InterruptObject (OUT) = Points to the interrupt object created on
255 * ServiceRoutine = Routine to be called when the device interrupts
256 * ServiceContext = Parameter to be passed to ServiceRoutine
257 * SpinLock = Initalized spinlock that will be used to synchronize
258 * access between the isr and other driver routines. This is
259 * required if the isr handles more than one vector or the
260 * driver has more than one isr
261 * Vector = Interrupt vector to allocate
262 * (returned from HalGetInterruptVector)
263 * Irql = DIRQL returned from HalGetInterruptVector
264 * SynchronizeIrql = DIRQL at which the isr will execute. This must
265 * be the highest of all the DIRQLs returned from
266 * HalGetInterruptVector if the driver has multiple
268 * InterruptMode = Specifies if the interrupt is LevelSensitive or
270 * ShareVector = Specifies if the vector can be shared
271 * ProcessorEnableMask = Processors on the isr can run
272 * FloatingSave = TRUE if the floating point stack should be saved when
273 * the isr runs. Must be false for x86 drivers
275 * IRQL: PASSIVE_LEVEL
280 PKINTERRUPT ListHead
;
282 ASSERT_IRQL(PASSIVE_LEVEL
);
284 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
287 * Check the parameters
289 if (Vector
>= NR_IRQS
)
291 return(STATUS_INVALID_PARAMETER
);
293 if (FloatingSave
== TRUE
)
295 return(STATUS_INVALID_PARAMETER
);
299 * Acquire the table spinlock
301 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
304 * Check if the vector is already in use that we can share it
306 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
307 if (!IsListEmpty(&isr_table
[Vector
]) &&
308 (ShareVector
== FALSE
|| ListHead
->Shareable
==FALSE
))
310 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
311 return(STATUS_INVALID_PARAMETER
);
315 isr_lock
[Vector
]=ExAllocatePool(NonPagedPool
,sizeof(KSPIN_LOCK
));
316 KeInitializeSpinLock(isr_lock
[Vector
]);
320 * Initialize interrupt object
322 (*InterruptObject
)=ExAllocatePool(NonPagedPool
,sizeof(KINTERRUPT
));
323 if ((*InterruptObject
)==NULL
)
325 return(STATUS_INSUFFICIENT_RESOURCES
);
327 (*InterruptObject
)->ServiceContext
= ServiceContext
;
328 (*InterruptObject
)->ServiceRoutine
= ServiceRoutine
;
329 (*InterruptObject
)->Vector
= Vector
;
330 (*InterruptObject
)->ProcessorEnableMask
= ProcessorEnableMask
;
331 (*InterruptObject
)->SynchLevel
= SynchronizeIrql
;
332 (*InterruptObject
)->Shareable
= ShareVector
;
333 (*InterruptObject
)->FloatingSave
= FALSE
;
334 (*InterruptObject
)->IrqLock
= isr_lock
[Vector
];
336 KeRaiseIrql((*InterruptObject
)->SynchLevel
,&synch_oldlvl
);
337 KeAcquireSpinLockAtDpcLevel((*InterruptObject
)->IrqLock
);
338 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
339 InsertTailList(&isr_table
[Vector
],&((*InterruptObject
)->Entry
));
340 DPRINT("%x %x\n",(*InterruptObject
)->Entry
.Flink
,
341 (*InterruptObject
)->Entry
.Blink
);
342 KeReleaseSpinLockFromDpcLevel((*InterruptObject
)->IrqLock
);
343 KeLowerIrql(synch_oldlvl
);
346 * Release the table spinlock
348 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
352 return(STATUS_SUCCESS
);
358 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
360 * FUNCTION: Releases a drivers isr
362 * InterruptObject = isr to release
367 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
368 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
369 RemoveEntryList(&InterruptObject
->Entry
);
370 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
377 HalDisableSystemInterrupt (
387 HalEnableSystemInterrupt (