1 /* $Id: irq.c,v 1.2 2000/07/24 23:51:46 ekohl 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
]);
107 VOID
KiInterruptDispatch (ULONG irq
)
109 * FUNCTION: Calls the irq specific handler for an irq
111 * irq = IRQ that has interrupted
121 * Notify the rest of the kernel of the raised irq level
123 HalBeginSystemInterrupt (irq
+IRQ_BASE
,
129 * NOTE: Only higher priority interrupts will get through
135 KiUpdateSystemTime();
139 DPRINT("KiInterruptDispatch(irq %d)\n",irq
);
141 * Iterate the list until one of the isr tells us its device interrupted
143 current
= isr_table
[irq
].Flink
;
144 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
145 DPRINT("current %x isr %x\n",current
,isr
);
146 while (current
!=(&isr_table
[irq
]) &&
147 !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
149 current
= current
->Flink
;
150 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
151 DPRINT("current %x isr %x\n",current
,isr
);
161 * Unmask the related irq
163 HalEnableSystemInterrupt (irq
+ IRQ_BASE
, 0, 0);
166 * If the processor level will drop below dispatch level on return then
167 * issue a DPC queue drain interrupt
169 if (old_level
< DISPATCH_LEVEL
)
171 HalEndSystemInterrupt (DISPATCH_LEVEL
, 0);
178 KiDispatchInterrupt();
179 PsDispatchThread(THREAD_STATE_RUNNABLE
);
186 HalEndSystemInterrupt (old_level
, 0);
191 static VOID
KeDumpIrqList(VOID
)
194 PLIST_ENTRY current_entry
;
197 for (i
=0;i
<NR_IRQS
;i
++)
199 DPRINT("For irq %x ",i
);
200 current_entry
= isr_table
[i
].Flink
;
201 current
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
202 while (current_entry
!=(&isr_table
[i
]))
204 DPRINT("Isr %x ",current
);
205 current_entry
= current_entry
->Flink
;
206 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
215 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
219 PKINTERRUPT ListHead
;
222 DPRINT("KeConnectInterrupt()\n");
224 Vector
= InterruptObject
->Vector
;
227 * Acquire the table spinlock
229 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
232 * Check if the vector is already in use that we can share it
234 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
235 if (!IsListEmpty(&isr_table
[Vector
]) &&
236 (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
))
238 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
239 return(STATUS_INVALID_PARAMETER
);
243 isr_lock
[Vector
]=ExAllocatePool(NonPagedPool
,sizeof(KSPIN_LOCK
));
244 KeInitializeSpinLock(isr_lock
[Vector
]);
247 InterruptObject
->IrqLock
= isr_lock
[Vector
];
249 KeRaiseIrql(InterruptObject
->SynchLevel
,&synch_oldlvl
);
250 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
251 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
252 InsertTailList(&isr_table
[Vector
],&InterruptObject
->Entry
);
253 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
,
254 InterruptObject
->Entry
.Blink
);
255 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
256 KeLowerIrql(synch_oldlvl
);
259 * Release the table spinlock
261 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
265 return STATUS_SUCCESS
;
271 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
273 * FUNCTION: Releases a drivers isr
275 * InterruptObject = isr to release
280 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
281 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
282 RemoveEntryList(&InterruptObject
->Entry
);
283 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
290 KeInitializeInterrupt(PKINTERRUPT InterruptObject
,
291 PKSERVICE_ROUTINE ServiceRoutine
,
292 PVOID ServiceContext
,
293 PKSPIN_LOCK SpinLock
,
296 KIRQL SynchronizeIrql
,
297 KINTERRUPT_MODE InterruptMode
,
299 KAFFINITY ProcessorEnableMask
,
300 BOOLEAN FloatingSave
)
302 InterruptObject
->ServiceContext
= ServiceContext
;
303 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
304 InterruptObject
->Vector
= Vector
;
305 InterruptObject
->ProcessorEnableMask
= ProcessorEnableMask
;
306 InterruptObject
->SynchLevel
= SynchronizeIrql
;
307 InterruptObject
->Shareable
= ShareVector
;
308 InterruptObject
->FloatingSave
= FALSE
;
310 return STATUS_SUCCESS
;
316 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
317 PKSERVICE_ROUTINE ServiceRoutine
,
318 PVOID ServiceContext
,
319 PKSPIN_LOCK SpinLock
,
322 KIRQL SynchronizeIrql
,
323 KINTERRUPT_MODE InterruptMode
,
325 KAFFINITY ProcessorEnableMask
,
326 BOOLEAN FloatingSave
)
328 * FUNCTION: Registers a driver's isr to be called when its device interrupts
330 * InterruptObject (OUT) = Points to the interrupt object created on
332 * ServiceRoutine = Routine to be called when the device interrupts
333 * ServiceContext = Parameter to be passed to ServiceRoutine
334 * SpinLock = Initalized spinlock that will be used to synchronize
335 * access between the isr and other driver routines. This is
336 * required if the isr handles more than one vector or the
337 * driver has more than one isr
338 * Vector = Interrupt vector to allocate
339 * (returned from HalGetInterruptVector)
340 * Irql = DIRQL returned from HalGetInterruptVector
341 * SynchronizeIrql = DIRQL at which the isr will execute. This must
342 * be the highest of all the DIRQLs returned from
343 * HalGetInterruptVector if the driver has multiple
345 * InterruptMode = Specifies if the interrupt is LevelSensitive or
347 * ShareVector = Specifies if the vector can be shared
348 * ProcessorEnableMask = Processors on the isr can run
349 * FloatingSave = TRUE if the floating point stack should be saved when
350 * the isr runs. Must be false for x86 drivers
352 * IRQL: PASSIVE_LEVEL
355 PKINTERRUPT Interrupt
;
356 NTSTATUS Status
= STATUS_SUCCESS
;
358 ASSERT_IRQL(PASSIVE_LEVEL
);
360 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
363 * Check the parameters
365 if (Vector
>= NR_IRQS
)
367 return(STATUS_INVALID_PARAMETER
);
369 if (FloatingSave
== TRUE
)
371 return(STATUS_INVALID_PARAMETER
);
375 * Initialize interrupt object
377 Interrupt
=ExAllocatePool(NonPagedPool
,sizeof(KINTERRUPT
));
380 return(STATUS_INSUFFICIENT_RESOURCES
);
383 Status
= KeInitializeInterrupt(Interrupt
,
394 if (!NT_SUCCESS(Status
))
396 ExFreePool(Interrupt
);
400 Status
= KeConnectInterrupt(Interrupt
);
401 if (!NT_SUCCESS(Status
))
403 ExFreePool(Interrupt
);
407 *InterruptObject
= Interrupt
;
409 return(STATUS_SUCCESS
);
415 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
417 * FUNCTION: Releases a drivers isr
419 * InterruptObject = isr to release
422 KeDisconnectInterrupt(InterruptObject
);
423 ExFreePool(InterruptObject
);