1 /* $Id: irq.c,v 1.1 2000/07/10 21:54:51 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>
26 #include <internal/halio.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,};
84 /* FUNCTIONS ****************************************************************/
86 #define PRESENT (0x8000)
87 #define I486_INTERRUPT_GATE (0xe00)
89 VOID
KeInitInterrupts (VOID
)
93 DPRINT("KeInitInterrupts ()\n",0);
96 * First mask off all interrupts from pic
103 * Setup the IDT entries to point to the interrupt handlers
105 for (i
=0;i
<NR_IRQS
;i
++)
107 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
108 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
110 InitializeListHead(&isr_table
[i
]);
115 VOID
KiInterruptDispatch (ULONG irq
)
117 * FUNCTION: Calls the irq specific handler for an irq
119 * irq = IRQ that has interrupted
129 * Notify the rest of the kernel of the raised irq level
131 old_level
= KeGetCurrentIrql();
134 DPRINT("old_level %d\n",old_level
);
136 KeSetCurrentIrql(HIGH_LEVEL
- irq
);
140 * NOTE: Only higher priority interrupts will get through
146 KiUpdateSystemTime();
150 DPRINT("KiInterruptDispatch(irq %d)\n",irq
);
152 * Iterate the list until one of the isr tells us its device interrupted
154 current
= isr_table
[irq
].Flink
;
155 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
156 DPRINT("current %x isr %x\n",current
,isr
);
157 while (current
!=(&isr_table
[irq
]) &&
158 !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
160 current
= current
->Flink
;
161 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
162 DPRINT("current %x isr %x\n",current
,isr
);
172 * Send EOI to the PIC
181 * Unmask the related irq
185 outb(0x21,inb(0x21)&(~(1<<irq
)));
189 outb(0xa1,inb(0xa1)&(~(1<<(irq
-8))));
193 * If the processor level will drop below dispatch level on return then
194 * issue a DPC queue drain interrupt
196 if (old_level
< DISPATCH_LEVEL
)
198 KeSetCurrentIrql(DISPATCH_LEVEL
);
205 KiDispatchInterrupt();
206 PsDispatchThread(THREAD_STATE_RUNNABLE
);
212 KeSetCurrentIrql(old_level
);
217 static VOID
KeDumpIrqList(VOID
)
220 PLIST_ENTRY current_entry
;
223 for (i
=0;i
<NR_IRQS
;i
++)
225 DPRINT("For irq %x ",i
);
226 current_entry
= isr_table
[i
].Flink
;
227 current
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
228 while (current_entry
!=(&isr_table
[i
]))
230 DPRINT("Isr %x ",current
);
231 current_entry
= current_entry
->Flink
;
232 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
241 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
245 PKINTERRUPT ListHead
;
248 DPRINT("KeConnectInterrupt()\n");
250 Vector
= InterruptObject
->Vector
;
253 * Acquire the table spinlock
255 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
258 * Check if the vector is already in use that we can share it
260 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
261 if (!IsListEmpty(&isr_table
[Vector
]) &&
262 (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
))
264 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
265 return(STATUS_INVALID_PARAMETER
);
269 isr_lock
[Vector
]=ExAllocatePool(NonPagedPool
,sizeof(KSPIN_LOCK
));
270 KeInitializeSpinLock(isr_lock
[Vector
]);
273 InterruptObject
->IrqLock
= isr_lock
[Vector
];
275 KeRaiseIrql(InterruptObject
->SynchLevel
,&synch_oldlvl
);
276 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
277 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
278 InsertTailList(&isr_table
[Vector
],&InterruptObject
->Entry
);
279 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
,
280 InterruptObject
->Entry
.Blink
);
281 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
282 KeLowerIrql(synch_oldlvl
);
285 * Release the table spinlock
287 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
291 return STATUS_SUCCESS
;
297 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
299 * FUNCTION: Releases a drivers isr
301 * InterruptObject = isr to release
306 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
307 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
308 RemoveEntryList(&InterruptObject
->Entry
);
309 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
316 KeInitializeInterrupt(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 InterruptObject
->ServiceContext
= ServiceContext
;
329 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
330 InterruptObject
->Vector
= Vector
;
331 InterruptObject
->ProcessorEnableMask
= ProcessorEnableMask
;
332 InterruptObject
->SynchLevel
= SynchronizeIrql
;
333 InterruptObject
->Shareable
= ShareVector
;
334 InterruptObject
->FloatingSave
= FALSE
;
336 return STATUS_SUCCESS
;
342 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
343 PKSERVICE_ROUTINE ServiceRoutine
,
344 PVOID ServiceContext
,
345 PKSPIN_LOCK SpinLock
,
348 KIRQL SynchronizeIrql
,
349 KINTERRUPT_MODE InterruptMode
,
351 KAFFINITY ProcessorEnableMask
,
352 BOOLEAN FloatingSave
)
354 * FUNCTION: Registers a driver's isr to be called when its device interrupts
356 * InterruptObject (OUT) = Points to the interrupt object created on
358 * ServiceRoutine = Routine to be called when the device interrupts
359 * ServiceContext = Parameter to be passed to ServiceRoutine
360 * SpinLock = Initalized spinlock that will be used to synchronize
361 * access between the isr and other driver routines. This is
362 * required if the isr handles more than one vector or the
363 * driver has more than one isr
364 * Vector = Interrupt vector to allocate
365 * (returned from HalGetInterruptVector)
366 * Irql = DIRQL returned from HalGetInterruptVector
367 * SynchronizeIrql = DIRQL at which the isr will execute. This must
368 * be the highest of all the DIRQLs returned from
369 * HalGetInterruptVector if the driver has multiple
371 * InterruptMode = Specifies if the interrupt is LevelSensitive or
373 * ShareVector = Specifies if the vector can be shared
374 * ProcessorEnableMask = Processors on the isr can run
375 * FloatingSave = TRUE if the floating point stack should be saved when
376 * the isr runs. Must be false for x86 drivers
378 * IRQL: PASSIVE_LEVEL
381 PKINTERRUPT Interrupt
;
382 NTSTATUS Status
= STATUS_SUCCESS
;
384 ASSERT_IRQL(PASSIVE_LEVEL
);
386 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
389 * Check the parameters
391 if (Vector
>= NR_IRQS
)
393 return(STATUS_INVALID_PARAMETER
);
395 if (FloatingSave
== TRUE
)
397 return(STATUS_INVALID_PARAMETER
);
401 * Initialize interrupt object
403 Interrupt
=ExAllocatePool(NonPagedPool
,sizeof(KINTERRUPT
));
406 return(STATUS_INSUFFICIENT_RESOURCES
);
409 Status
= KeInitializeInterrupt(Interrupt
,
420 if (!NT_SUCCESS(Status
))
422 ExFreePool(Interrupt
);
426 Status
= KeConnectInterrupt(Interrupt
);
427 if (!NT_SUCCESS(Status
))
429 ExFreePool(Interrupt
);
433 *InterruptObject
= Interrupt
;
435 return(STATUS_SUCCESS
);
441 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
443 * FUNCTION: Releases a drivers isr
445 * InterruptObject = isr to release
448 KeDisconnectInterrupt(InterruptObject
);
449 ExFreePool(InterruptObject
);