1 /* $Id: irq.c,v 1.5 2001/02/06 00:11:19 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/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/ke.h>
24 #include <internal/ps.h>
25 #include <internal/i386/segment.h>
28 #include <internal/debug.h>
30 /* GLOBALS *****************************************************************/
33 #define IRQ_BASE (0x40)
35 void irq_handler_0(void);
36 void irq_handler_1(void);
37 void irq_handler_2(void);
38 void irq_handler_3(void);
39 void irq_handler_4(void);
40 void irq_handler_5(void);
41 void irq_handler_6(void);
42 void irq_handler_7(void);
43 void irq_handler_8(void);
44 void irq_handler_9(void);
45 void irq_handler_10(void);
46 void irq_handler_11(void);
47 void irq_handler_12(void);
48 void irq_handler_13(void);
49 void irq_handler_14(void);
50 void irq_handler_15(void);
52 static unsigned int irq_handler
[NR_IRQS
]=
73 * PURPOSE: Object describing each isr
74 * NOTE: The data in this table is only modified at passsive level but can
75 * be accessed at any irq level.
78 static LIST_ENTRY isr_table
[NR_IRQS
]={{NULL
,NULL
},};
79 static PKSPIN_LOCK isr_lock
[NR_IRQS
] = {NULL
,};
80 static KSPIN_LOCK isr_table_lock
= {0,};
83 /* FUNCTIONS ****************************************************************/
85 #define PRESENT (0x8000)
86 #define I486_INTERRUPT_GATE (0xe00)
88 VOID
KeInitInterrupts (VOID
)
92 DPRINT("KeInitInterrupts ()\n",0);
95 * Setup the IDT entries to point to the interrupt handlers
97 for (i
=0;i
<NR_IRQS
;i
++)
99 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
100 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
102 InitializeListHead(&isr_table
[i
]);
106 typedef struct _KIRQ_TRAPFRAME
123 } KIRQ_TRAPFRAME
, *PKIRQ_TRAPFRAME
;
126 KiInterruptDispatch (ULONG irq
, PKIRQ_TRAPFRAME Trapframe
)
128 * FUNCTION: Calls the irq specific handler for an irq
130 * irq = IRQ that has interrupted
140 * Notify the rest of the kernel of the raised irq level
142 HalBeginSystemInterrupt (irq
+IRQ_BASE
,
148 * NOTE: Only higher priority interrupts will get through
154 KiUpdateSystemTime();
158 DPRINT("KiInterruptDispatch(irq %d)\n",irq
);
160 * Iterate the list until one of the isr tells us its device interrupted
162 current
= isr_table
[irq
].Flink
;
163 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
164 DPRINT("current %x isr %x\n",current
,isr
);
165 while (current
!=(&isr_table
[irq
]) &&
166 !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
168 current
= current
->Flink
;
169 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
170 DPRINT("current %x isr %x\n",current
,isr
);
180 * Unmask the related irq
182 HalEnableSystemInterrupt (irq
+ IRQ_BASE
, 0, 0);
185 * If the processor level will drop below dispatch level on return then
186 * issue a DPC queue drain interrupt
188 if (old_level
< DISPATCH_LEVEL
)
190 HalEndSystemInterrupt (DISPATCH_LEVEL
, 0);
193 if (KeGetCurrentThread() != NULL
)
195 KeGetCurrentThread()->LastEip
= Trapframe
->Eip
;
197 KiDispatchInterrupt();
200 PsDispatchThread(THREAD_STATE_RUNNABLE
);
202 if (KeGetCurrentThread() != NULL
&&
203 KeGetCurrentThread()->Alerted
[1] != 0 &&
204 Trapframe
->Cs
!= KERNEL_CS
)
206 HalEndSystemInterrupt (APC_LEVEL
, 0);
207 KiDeliverNormalApc();
211 HalEndSystemInterrupt (old_level
, 0);
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 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
243 PKINTERRUPT ListHead
;
246 DPRINT("KeConnectInterrupt()\n");
248 Vector
= InterruptObject
->Vector
;
251 * Acquire the table spinlock
253 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
256 * Check if the vector is already in use that we can share it
258 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
259 if (!IsListEmpty(&isr_table
[Vector
]) &&
260 (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
))
262 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
263 return(STATUS_INVALID_PARAMETER
);
267 isr_lock
[Vector
]=ExAllocatePool(NonPagedPool
,sizeof(KSPIN_LOCK
));
268 KeInitializeSpinLock(isr_lock
[Vector
]);
271 InterruptObject
->IrqLock
= isr_lock
[Vector
];
273 KeRaiseIrql(InterruptObject
->SynchLevel
,&synch_oldlvl
);
274 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
275 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
276 InsertTailList(&isr_table
[Vector
],&InterruptObject
->Entry
);
277 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
,
278 InterruptObject
->Entry
.Blink
);
279 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
280 KeLowerIrql(synch_oldlvl
);
283 * Release the table spinlock
285 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
289 return STATUS_SUCCESS
;
294 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
296 * FUNCTION: Releases a drivers isr
298 * InterruptObject = isr to release
303 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
304 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
305 RemoveEntryList(&InterruptObject
->Entry
);
306 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
313 KeInitializeInterrupt(PKINTERRUPT InterruptObject
,
314 PKSERVICE_ROUTINE ServiceRoutine
,
315 PVOID ServiceContext
,
316 PKSPIN_LOCK SpinLock
,
319 KIRQL SynchronizeIrql
,
320 KINTERRUPT_MODE InterruptMode
,
322 KAFFINITY ProcessorEnableMask
,
323 BOOLEAN FloatingSave
)
325 InterruptObject
->ServiceContext
= ServiceContext
;
326 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
327 InterruptObject
->Vector
= Vector
;
328 InterruptObject
->ProcessorEnableMask
= ProcessorEnableMask
;
329 InterruptObject
->SynchLevel
= SynchronizeIrql
;
330 InterruptObject
->Shareable
= ShareVector
;
331 InterruptObject
->FloatingSave
= FALSE
;
333 return STATUS_SUCCESS
;
339 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
340 PKSERVICE_ROUTINE ServiceRoutine
,
341 PVOID ServiceContext
,
342 PKSPIN_LOCK SpinLock
,
345 KIRQL SynchronizeIrql
,
346 KINTERRUPT_MODE InterruptMode
,
348 KAFFINITY ProcessorEnableMask
,
349 BOOLEAN FloatingSave
)
351 * FUNCTION: Registers a driver's isr to be called when its device interrupts
353 * InterruptObject (OUT) = Points to the interrupt object created on
355 * ServiceRoutine = Routine to be called when the device interrupts
356 * ServiceContext = Parameter to be passed to ServiceRoutine
357 * SpinLock = Initalized spinlock that will be used to synchronize
358 * access between the isr and other driver routines. This is
359 * required if the isr handles more than one vector or the
360 * driver has more than one isr
361 * Vector = Interrupt vector to allocate
362 * (returned from HalGetInterruptVector)
363 * Irql = DIRQL returned from HalGetInterruptVector
364 * SynchronizeIrql = DIRQL at which the isr will execute. This must
365 * be the highest of all the DIRQLs returned from
366 * HalGetInterruptVector if the driver has multiple
368 * InterruptMode = Specifies if the interrupt is LevelSensitive or
370 * ShareVector = Specifies if the vector can be shared
371 * ProcessorEnableMask = Processors on the isr can run
372 * FloatingSave = TRUE if the floating point stack should be saved when
373 * the isr runs. Must be false for x86 drivers
375 * IRQL: PASSIVE_LEVEL
378 PKINTERRUPT Interrupt
;
379 NTSTATUS Status
= STATUS_SUCCESS
;
381 ASSERT_IRQL(PASSIVE_LEVEL
);
383 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
386 * Check the parameters
388 if (Vector
>= NR_IRQS
)
390 return(STATUS_INVALID_PARAMETER
);
392 if (FloatingSave
== TRUE
)
394 return(STATUS_INVALID_PARAMETER
);
398 * Initialize interrupt object
400 Interrupt
=ExAllocatePool(NonPagedPool
,sizeof(KINTERRUPT
));
403 return(STATUS_INSUFFICIENT_RESOURCES
);
406 Status
= KeInitializeInterrupt(Interrupt
,
417 if (!NT_SUCCESS(Status
))
419 ExFreePool(Interrupt
);
423 Status
= KeConnectInterrupt(Interrupt
);
424 if (!NT_SUCCESS(Status
))
426 ExFreePool(Interrupt
);
430 *InterruptObject
= Interrupt
;
432 return(STATUS_SUCCESS
);
437 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
439 * FUNCTION: Releases a drivers isr
441 * InterruptObject = isr to release
444 KeDisconnectInterrupt(InterruptObject
);
445 ExFreePool(InterruptObject
);