1 /* $Id: irq.c,v 1.6 2001/03/07 16:48:43 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>
26 #include <internal/pool.h>
29 #include <internal/debug.h>
31 /* GLOBALS *****************************************************************/
34 #define IRQ_BASE (0x40)
36 void irq_handler_0(void);
37 void irq_handler_1(void);
38 void irq_handler_2(void);
39 void irq_handler_3(void);
40 void irq_handler_4(void);
41 void irq_handler_5(void);
42 void irq_handler_6(void);
43 void irq_handler_7(void);
44 void irq_handler_8(void);
45 void irq_handler_9(void);
46 void irq_handler_10(void);
47 void irq_handler_11(void);
48 void irq_handler_12(void);
49 void irq_handler_13(void);
50 void irq_handler_14(void);
51 void irq_handler_15(void);
53 static unsigned int irq_handler
[NR_IRQS
]=
74 * PURPOSE: Object describing each isr
75 * NOTE: The data in this table is only modified at passsive level but can
76 * be accessed at any irq level.
79 static LIST_ENTRY isr_table
[NR_IRQS
]={{NULL
,NULL
},};
80 static PKSPIN_LOCK isr_lock
[NR_IRQS
] = {NULL
,};
81 static KSPIN_LOCK isr_table_lock
= {0,};
83 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
84 #define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R')
86 /* FUNCTIONS ****************************************************************/
88 #define PRESENT (0x8000)
89 #define I486_INTERRUPT_GATE (0xe00)
91 VOID
KeInitInterrupts (VOID
)
95 DPRINT("KeInitInterrupts ()\n",0);
98 * Setup the IDT entries to point to the interrupt handlers
100 for (i
=0;i
<NR_IRQS
;i
++)
102 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
103 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
105 InitializeListHead(&isr_table
[i
]);
109 typedef struct _KIRQ_TRAPFRAME
126 } KIRQ_TRAPFRAME
, *PKIRQ_TRAPFRAME
;
129 KiInterruptDispatch (ULONG irq
, PKIRQ_TRAPFRAME Trapframe
)
131 * FUNCTION: Calls the irq specific handler for an irq
133 * irq = IRQ that has interrupted
143 * Notify the rest of the kernel of the raised irq level
145 HalBeginSystemInterrupt (irq
+IRQ_BASE
,
151 * NOTE: Only higher priority interrupts will get through
157 KiUpdateSystemTime();
161 DPRINT("KiInterruptDispatch(irq %d)\n",irq
);
163 * Iterate the list until one of the isr tells us its device interrupted
165 current
= isr_table
[irq
].Flink
;
166 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
167 DPRINT("current %x isr %x\n",current
,isr
);
168 while (current
!=(&isr_table
[irq
]) &&
169 !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
171 current
= current
->Flink
;
172 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
173 DPRINT("current %x isr %x\n",current
,isr
);
183 * Unmask the related irq
185 HalEnableSystemInterrupt (irq
+ IRQ_BASE
, 0, 0);
188 * If the processor level will drop below dispatch level on return then
189 * issue a DPC queue drain interrupt
191 if (old_level
< DISPATCH_LEVEL
)
193 HalEndSystemInterrupt (DISPATCH_LEVEL
, 0);
196 if (KeGetCurrentThread() != NULL
)
198 KeGetCurrentThread()->LastEip
= Trapframe
->Eip
;
200 KiDispatchInterrupt();
203 PsDispatchThread(THREAD_STATE_RUNNABLE
);
205 if (KeGetCurrentThread() != NULL
&&
206 KeGetCurrentThread()->Alerted
[1] != 0 &&
207 Trapframe
->Cs
!= KERNEL_CS
)
209 HalEndSystemInterrupt (APC_LEVEL
, 0);
210 KiDeliverNormalApc();
214 HalEndSystemInterrupt (old_level
, 0);
222 PLIST_ENTRY current_entry
;
225 for (i
=0;i
<NR_IRQS
;i
++)
227 DPRINT("For irq %x ",i
);
228 current_entry
= isr_table
[i
].Flink
;
229 current
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
230 while (current_entry
!=(&isr_table
[i
]))
232 DPRINT("Isr %x ",current
);
233 current_entry
= current_entry
->Flink
;
234 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
242 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
246 PKINTERRUPT ListHead
;
249 DPRINT("KeConnectInterrupt()\n");
251 Vector
= InterruptObject
->Vector
;
254 * Acquire the table spinlock
256 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
259 * Check if the vector is already in use that we can share it
261 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
262 if (!IsListEmpty(&isr_table
[Vector
]) &&
263 (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
))
265 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
266 return(STATUS_INVALID_PARAMETER
);
271 ExAllocatePoolWithTag(NonPagedPool
, sizeof(KSPIN_LOCK
),
273 KeInitializeSpinLock(isr_lock
[Vector
]);
276 InterruptObject
->IrqLock
= isr_lock
[Vector
];
278 KeRaiseIrql(InterruptObject
->SynchLevel
,&synch_oldlvl
);
279 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
280 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
281 InsertTailList(&isr_table
[Vector
],&InterruptObject
->Entry
);
282 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
,
283 InterruptObject
->Entry
.Blink
);
284 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
285 KeLowerIrql(synch_oldlvl
);
288 * Release the table spinlock
290 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
294 return STATUS_SUCCESS
;
299 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
301 * FUNCTION: Releases a drivers isr
303 * InterruptObject = isr to release
308 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
309 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
310 RemoveEntryList(&InterruptObject
->Entry
);
311 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
318 KeInitializeInterrupt(PKINTERRUPT InterruptObject
,
319 PKSERVICE_ROUTINE ServiceRoutine
,
320 PVOID ServiceContext
,
321 PKSPIN_LOCK SpinLock
,
324 KIRQL SynchronizeIrql
,
325 KINTERRUPT_MODE InterruptMode
,
327 KAFFINITY ProcessorEnableMask
,
328 BOOLEAN FloatingSave
)
330 InterruptObject
->ServiceContext
= ServiceContext
;
331 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
332 InterruptObject
->Vector
= Vector
;
333 InterruptObject
->ProcessorEnableMask
= ProcessorEnableMask
;
334 InterruptObject
->SynchLevel
= SynchronizeIrql
;
335 InterruptObject
->Shareable
= ShareVector
;
336 InterruptObject
->FloatingSave
= FALSE
;
338 return STATUS_SUCCESS
;
344 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
345 PKSERVICE_ROUTINE ServiceRoutine
,
346 PVOID ServiceContext
,
347 PKSPIN_LOCK SpinLock
,
350 KIRQL SynchronizeIrql
,
351 KINTERRUPT_MODE InterruptMode
,
353 KAFFINITY ProcessorEnableMask
,
354 BOOLEAN FloatingSave
)
356 * FUNCTION: Registers a driver's isr to be called when its device interrupts
358 * InterruptObject (OUT) = Points to the interrupt object created on
360 * ServiceRoutine = Routine to be called when the device interrupts
361 * ServiceContext = Parameter to be passed to ServiceRoutine
362 * SpinLock = Initalized spinlock that will be used to synchronize
363 * access between the isr and other driver routines. This is
364 * required if the isr handles more than one vector or the
365 * driver has more than one isr
366 * Vector = Interrupt vector to allocate
367 * (returned from HalGetInterruptVector)
368 * Irql = DIRQL returned from HalGetInterruptVector
369 * SynchronizeIrql = DIRQL at which the isr will execute. This must
370 * be the highest of all the DIRQLs returned from
371 * HalGetInterruptVector if the driver has multiple
373 * InterruptMode = Specifies if the interrupt is LevelSensitive or
375 * ShareVector = Specifies if the vector can be shared
376 * ProcessorEnableMask = Processors on the isr can run
377 * FloatingSave = TRUE if the floating point stack should be saved when
378 * the isr runs. Must be false for x86 drivers
380 * IRQL: PASSIVE_LEVEL
383 PKINTERRUPT Interrupt
;
384 NTSTATUS Status
= STATUS_SUCCESS
;
386 ASSERT_IRQL(PASSIVE_LEVEL
);
388 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
391 * Check the parameters
393 if (Vector
>= NR_IRQS
)
395 return(STATUS_INVALID_PARAMETER
);
397 if (FloatingSave
== TRUE
)
399 return(STATUS_INVALID_PARAMETER
);
403 * Initialize interrupt object
405 Interrupt
=ExAllocatePoolWithTag(NonPagedPool
,sizeof(KINTERRUPT
),
409 return(STATUS_INSUFFICIENT_RESOURCES
);
412 Status
= KeInitializeInterrupt(Interrupt
,
423 if (!NT_SUCCESS(Status
))
425 ExFreePool(Interrupt
);
429 Status
= KeConnectInterrupt(Interrupt
);
430 if (!NT_SUCCESS(Status
))
432 ExFreePool(Interrupt
);
436 *InterruptObject
= Interrupt
;
438 return(STATUS_SUCCESS
);
443 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
445 * FUNCTION: Releases a drivers isr
447 * InterruptObject = isr to release
450 KeDisconnectInterrupt(InterruptObject
);
451 ExFreePool(InterruptObject
);