2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/irq.c
5 * PURPOSE: Manages the Kernel's IRQ support for external drivers,
6 * for the purpopses of connecting, disconnecting and setting
7 * up ISRs for drivers. The backend behind the Io* Interrupt
9 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
10 * Alex Ionescu (alex.ionescu@reactos.org)
13 /* INCLUDES *****************************************************************/
19 extern UCHAR KiInterruptDispatchTemplate
[16];
20 extern UCHAR KiUnexpectedRange
[];
21 extern UCHAR KiUnexpectedRangeEnd
[];
22 void KiInterruptDispatch(void);
25 /* FUNCTIONS ****************************************************************/
29 KeInitializeInterrupt(
30 IN PKINTERRUPT Interrupt
,
31 IN PKSERVICE_ROUTINE ServiceRoutine
,
32 IN PVOID ServiceContext
,
33 IN PKSPIN_LOCK SpinLock
,
36 IN KIRQL SynchronizeIrql
,
37 IN KINTERRUPT_MODE InterruptMode
,
38 IN BOOLEAN ShareVector
,
39 IN CHAR ProcessorNumber
,
40 IN BOOLEAN FloatingSave
)
43 /* Initialize the header */
44 Interrupt
->Type
= InterruptObject
;
45 Interrupt
->Size
= sizeof(KINTERRUPT
);
47 /* If no Spinlock is given, use the internal */
48 if (!SpinLock
) SpinLock
= &Interrupt
->SpinLock
;
49 KeInitializeSpinLock(&Interrupt
->SpinLock
);
51 /* Set the given parameters */
52 Interrupt
->ServiceRoutine
= ServiceRoutine
;
53 Interrupt
->ServiceContext
= ServiceContext
;
54 Interrupt
->ActualLock
= SpinLock
;
55 Interrupt
->Vector
= Vector
;
56 Interrupt
->Irql
= Irql
;
57 Interrupt
->SynchronizeIrql
= SynchronizeIrql
;
58 Interrupt
->Mode
= InterruptMode
;
59 Interrupt
->ShareVector
= ShareVector
;
60 Interrupt
->Number
= ProcessorNumber
;
61 Interrupt
->FloatingSave
= FloatingSave
;
63 /* Set initial values */
64 Interrupt
->TickCount
= 0;
65 Interrupt
->Connected
= FALSE
;
66 Interrupt
->ServiceCount
= 0;
67 Interrupt
->DispatchCount
= 0;
68 Interrupt
->TrapFrame
= NULL
;
69 Interrupt
->Reserved
= 0;
71 /* Copy the dispatch code (its location independent, no need to patch it) */
72 RtlCopyMemory(Interrupt
->DispatchCode
,
73 KiInterruptDispatchTemplate
,
74 sizeof(Interrupt
->DispatchCode
));
76 Interrupt
->DispatchAddress
= 0;
81 KeConnectInterrupt(IN PKINTERRUPT Interrupt
)
85 ASSERT(Interrupt
->Vector
<= MAXIMUM_IDTVECTOR
);
86 ASSERT(Interrupt
->Number
< KeNumberProcessors
);
87 ASSERT(Interrupt
->Irql
<= HIGH_LEVEL
);
89 /* Check if its already connected */
90 if (Interrupt
->Connected
) return TRUE
;
92 /* Query the current handler */
93 CurrentHandler
= KeQueryInterruptHandler(Interrupt
->Vector
);
95 /* Check if the vector is already unused */
96 if ((CurrentHandler
>= (PVOID
)KiUnexpectedRange
) &&
97 (CurrentHandler
<= (PVOID
)KiUnexpectedRangeEnd
))
99 /* Initialize the list for chained interrupts */
100 InitializeListHead(&Interrupt
->InterruptListEntry
);
102 /* Set normal dispatch address */
103 Interrupt
->DispatchAddress
= KiInterruptDispatch
;
105 /* Set the new handler */
106 KeRegisterInterruptHandler(Interrupt
->Vector
,
107 Interrupt
->DispatchCode
);
109 if (!HalEnableSystemInterrupt(Interrupt
->Vector
,
113 /* Didn't work, restore old handler */
114 DPRINT1("HalEnableSystemInterrupt failed\n");
115 KeRegisterInterruptHandler(Interrupt
->Vector
, CurrentHandler
);
119 /* Mark as connected */
120 Interrupt
->Connected
= TRUE
;
133 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt
)
142 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt
,
143 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine
,
144 IN PVOID SynchronizeContext OPTIONAL
)
150 OldIrql
= KfRaiseIrql(Interrupt
->SynchronizeIrql
);
152 /* Acquire interrupt spinlock */
153 KeAcquireSpinLockAtDpcLevel(Interrupt
->ActualLock
);
155 /* Call the routine */
156 Success
= SynchronizeRoutine(SynchronizeContext
);
159 KeReleaseSpinLockFromDpcLevel(Interrupt
->ActualLock
);
162 KeLowerIrql(OldIrql
);