1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS Kernel
3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory
4c2c66affSColin Finck * FILE: ntoskrnl/ke/i386/irqobj.c
5c2c66affSColin Finck * PURPOSE: Manages the Kernel's IRQ support for external drivers,
6c2c66affSColin Finck * for the purposes of connecting, disconnecting and setting
7c2c66affSColin Finck * up ISRs for drivers. The backend behind the Io* Interrupt
8c2c66affSColin Finck * routines.
9c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10c2c66affSColin Finck */
11c2c66affSColin Finck
12c2c66affSColin Finck /* INCLUDES *****************************************************************/
13c2c66affSColin Finck
14c2c66affSColin Finck #include <ntoskrnl.h>
15c2c66affSColin Finck #define NDEBUG
16c2c66affSColin Finck #include <debug.h>
17c2c66affSColin Finck
18c2c66affSColin Finck /* GLOBALS *******************************************************************/
19c2c66affSColin Finck
20c2c66affSColin Finck ULONG KiISRTimeout = 55;
21c2c66affSColin Finck USHORT KiISROverflow = 30000;
22c2c66affSColin Finck extern ULONG NTAPI KiChainedDispatch2ndLvl(VOID);
23c2c66affSColin Finck
24c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
25c2c66affSColin Finck
26c2c66affSColin Finck VOID
27c2c66affSColin Finck NTAPI
KiGetVectorDispatch(IN ULONG Vector,IN PDISPATCH_INFO Dispatch)28c2c66affSColin Finck KiGetVectorDispatch(IN ULONG Vector,
29c2c66affSColin Finck IN PDISPATCH_INFO Dispatch)
30c2c66affSColin Finck {
31c2c66affSColin Finck PKINTERRUPT_ROUTINE Handler;
32c2c66affSColin Finck PVOID Current;
33c2c66affSColin Finck UCHAR Type;
34c2c66affSColin Finck UCHAR Entry;
35c2c66affSColin Finck
36c2c66affSColin Finck /* Check if this is a primary or 2nd-level dispatch */
37c2c66affSColin Finck Type = HalSystemVectorDispatchEntry(Vector,
38c2c66affSColin Finck &Dispatch->FlatDispatch,
39c2c66affSColin Finck &Dispatch->NoDispatch);
40c2c66affSColin Finck ASSERT(Type == 0);
41c2c66affSColin Finck
42c2c66affSColin Finck /* Get the IDT entry for this vector */
43c2c66affSColin Finck Entry = HalVectorToIDTEntry(Vector);
44c2c66affSColin Finck
45c2c66affSColin Finck /* Setup the unhandled dispatch */
46c2c66affSColin Finck Dispatch->NoDispatch = (PVOID)(((ULONG_PTR)&KiStartUnexpectedRange) +
47c2c66affSColin Finck (Entry - PRIMARY_VECTOR_BASE) *
48c2c66affSColin Finck KiUnexpectedEntrySize);
49c2c66affSColin Finck
50c2c66affSColin Finck /* Setup the handlers */
51c2c66affSColin Finck Dispatch->InterruptDispatch = (PVOID)KiInterruptDispatch;
52c2c66affSColin Finck Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported
53c2c66affSColin Finck Dispatch->ChainedDispatch = (PVOID)KiChainedDispatch;
54c2c66affSColin Finck Dispatch->FlatDispatch = NULL;
55c2c66affSColin Finck
56c2c66affSColin Finck /* Get the current handler */
57c2c66affSColin Finck Current = KeQueryInterruptHandler(Vector);
58c2c66affSColin Finck
59c2c66affSColin Finck /* Set the interrupt */
60c2c66affSColin Finck Dispatch->Interrupt = CONTAINING_RECORD(Current,
61c2c66affSColin Finck KINTERRUPT,
62c2c66affSColin Finck DispatchCode);
63c2c66affSColin Finck
64c2c66affSColin Finck /* Check what this interrupt is connected to */
65c2c66affSColin Finck if ((PKINTERRUPT_ROUTINE)Current == Dispatch->NoDispatch)
66c2c66affSColin Finck {
67c2c66affSColin Finck /* Not connected */
68c2c66affSColin Finck Dispatch->Type = NoConnect;
69c2c66affSColin Finck }
70c2c66affSColin Finck else
71c2c66affSColin Finck {
72c2c66affSColin Finck /* Get the handler */
73c2c66affSColin Finck Handler = Dispatch->Interrupt->DispatchAddress;
74c2c66affSColin Finck if (Handler == Dispatch->ChainedDispatch)
75c2c66affSColin Finck {
76c2c66affSColin Finck /* It's a chained interrupt */
77c2c66affSColin Finck Dispatch->Type = ChainConnect;
78c2c66affSColin Finck }
79c2c66affSColin Finck else if ((Handler == Dispatch->InterruptDispatch) ||
80c2c66affSColin Finck (Handler == Dispatch->FloatingDispatch))
81c2c66affSColin Finck {
82c2c66affSColin Finck /* It's unchained */
83c2c66affSColin Finck Dispatch->Type = NormalConnect;
84c2c66affSColin Finck }
85c2c66affSColin Finck else
86c2c66affSColin Finck {
87c2c66affSColin Finck /* Unknown */
88c2c66affSColin Finck Dispatch->Type = UnknownConnect;
89c2c66affSColin Finck }
90c2c66affSColin Finck }
91c2c66affSColin Finck }
92c2c66affSColin Finck
93c2c66affSColin Finck VOID
94c2c66affSColin Finck NTAPI
KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,IN CONNECT_TYPE Type)95c2c66affSColin Finck KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
96c2c66affSColin Finck IN CONNECT_TYPE Type)
97c2c66affSColin Finck {
98c2c66affSColin Finck DISPATCH_INFO Dispatch;
99c2c66affSColin Finck PKINTERRUPT_ROUTINE Handler;
100c2c66affSColin Finck
101c2c66affSColin Finck /* Get vector data */
102c2c66affSColin Finck KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
103c2c66affSColin Finck
104c2c66affSColin Finck /* Check if we're only disconnecting */
105c2c66affSColin Finck if (Type == NoConnect)
106c2c66affSColin Finck {
107c2c66affSColin Finck /* Set the handler to NoDispatch */
108c2c66affSColin Finck Handler = Dispatch.NoDispatch;
109c2c66affSColin Finck }
110c2c66affSColin Finck else
111c2c66affSColin Finck {
112c2c66affSColin Finck /* Get the right handler */
113c2c66affSColin Finck Handler = (Type == NormalConnect) ?
114c2c66affSColin Finck Dispatch.InterruptDispatch:
115c2c66affSColin Finck Dispatch.ChainedDispatch;
116c2c66affSColin Finck ASSERT(Interrupt->FloatingSave == FALSE);
117c2c66affSColin Finck
118c2c66affSColin Finck /* Set the handler */
119c2c66affSColin Finck Interrupt->DispatchAddress = Handler;
120c2c66affSColin Finck
121c2c66affSColin Finck /* Read note in trap.s -- patching not needed since JMP is static */
122c2c66affSColin Finck
123c2c66affSColin Finck /* Now set the final handler address */
124c2c66affSColin Finck ASSERT(Dispatch.FlatDispatch == NULL);
125c2c66affSColin Finck Handler = (PVOID)&Interrupt->DispatchCode;
126c2c66affSColin Finck }
127c2c66affSColin Finck
128c2c66affSColin Finck /* Register the interrupt */
129c2c66affSColin Finck KeRegisterInterruptHandler(Interrupt->Vector, Handler);
130c2c66affSColin Finck }
131c2c66affSColin Finck
132c2c66affSColin Finck FORCEINLINE
133c2c66affSColin Finck DECLSPEC_NORETURN
134c2c66affSColin Finck VOID
KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,IN KIRQL OldIrql,IN BOOLEAN Spurious)135c2c66affSColin Finck KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,
136c2c66affSColin Finck IN KIRQL OldIrql,
137c2c66affSColin Finck IN BOOLEAN Spurious)
138c2c66affSColin Finck {
139c2c66affSColin Finck /* Check if this was a real interrupt */
140c2c66affSColin Finck if (!Spurious)
141c2c66affSColin Finck {
142c2c66affSColin Finck /* It was, disable interrupts and restore the IRQL */
143c2c66affSColin Finck _disable();
144c2c66affSColin Finck HalEndSystemInterrupt(OldIrql, TrapFrame);
145c2c66affSColin Finck }
146c2c66affSColin Finck
147c2c66affSColin Finck /* Now exit the trap */
148c2c66affSColin Finck KiEoiHelper(TrapFrame);
149c2c66affSColin Finck }
150c2c66affSColin Finck
151c2c66affSColin Finck DECLSPEC_NORETURN
152c2c66affSColin Finck VOID
153c2c66affSColin Finck __cdecl
KiUnexpectedInterrupt(VOID)154c2c66affSColin Finck KiUnexpectedInterrupt(VOID)
155c2c66affSColin Finck {
156c2c66affSColin Finck /* Crash the machine */
157c2c66affSColin Finck KeBugCheck(TRAP_CAUSE_UNKNOWN);
158c2c66affSColin Finck }
159c2c66affSColin Finck
160c2c66affSColin Finck VOID
161c2c66affSColin Finck FASTCALL
KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame)162c2c66affSColin Finck KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame)
163c2c66affSColin Finck {
164c2c66affSColin Finck KIRQL OldIrql;
165c2c66affSColin Finck
166c2c66affSColin Finck /* Enter trap */
167c2c66affSColin Finck KiEnterInterruptTrap(TrapFrame);
168c2c66affSColin Finck
169c2c66affSColin Finck /* Increase interrupt count */
170c2c66affSColin Finck KeGetCurrentPrcb()->InterruptCount++;
171c2c66affSColin Finck
172c2c66affSColin Finck /* Start the interrupt */
173c2c66affSColin Finck if (HalBeginSystemInterrupt(HIGH_LEVEL, TrapFrame->ErrCode, &OldIrql))
174c2c66affSColin Finck {
175c2c66affSColin Finck /* Warn user */
176c2c66affSColin Finck DPRINT1("\n\x7\x7!!! Unexpected Interrupt 0x%02lx !!!\n", TrapFrame->ErrCode);
177c2c66affSColin Finck
178c2c66affSColin Finck /* Now call the epilogue code */
179c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, FALSE);
180c2c66affSColin Finck }
181c2c66affSColin Finck else
182c2c66affSColin Finck {
183c2c66affSColin Finck /* Now call the epilogue code */
184c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, TRUE);
185c2c66affSColin Finck }
186c2c66affSColin Finck }
187c2c66affSColin Finck
188c2c66affSColin Finck typedef
189c2c66affSColin Finck VOID
190c2c66affSColin Finck (FASTCALL *PKI_INTERRUPT_DISPATCH)(
191c2c66affSColin Finck IN PKTRAP_FRAME TrapFrame,
192c2c66affSColin Finck IN PKINTERRUPT Interrupt
193c2c66affSColin Finck );
194c2c66affSColin Finck
195c2c66affSColin Finck VOID
196c2c66affSColin Finck FASTCALL
KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)197c2c66affSColin Finck KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,
198c2c66affSColin Finck IN PKINTERRUPT Interrupt)
199c2c66affSColin Finck {
200c2c66affSColin Finck KIRQL OldIrql;
201c2c66affSColin Finck
202c2c66affSColin Finck /* Increase interrupt count */
203c2c66affSColin Finck KeGetCurrentPrcb()->InterruptCount++;
204c2c66affSColin Finck
205c2c66affSColin Finck /* Begin the interrupt, making sure it's not spurious */
206c2c66affSColin Finck if (HalBeginSystemInterrupt(Interrupt->SynchronizeIrql,
207c2c66affSColin Finck Interrupt->Vector,
208c2c66affSColin Finck &OldIrql))
209c2c66affSColin Finck {
210c2c66affSColin Finck /* Acquire interrupt lock */
211c2c66affSColin Finck KxAcquireSpinLock(Interrupt->ActualLock);
212c2c66affSColin Finck
213c2c66affSColin Finck /* Call the ISR */
214c2c66affSColin Finck Interrupt->ServiceRoutine(Interrupt, Interrupt->ServiceContext);
215c2c66affSColin Finck
216c2c66affSColin Finck /* Release interrupt lock */
217c2c66affSColin Finck KxReleaseSpinLock(Interrupt->ActualLock);
218c2c66affSColin Finck
219c2c66affSColin Finck /* Now call the epilogue code */
220c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, FALSE);
221c2c66affSColin Finck }
222c2c66affSColin Finck else
223c2c66affSColin Finck {
224c2c66affSColin Finck /* Now call the epilogue code */
225c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, TRUE);
226c2c66affSColin Finck }
227c2c66affSColin Finck }
228c2c66affSColin Finck
229c2c66affSColin Finck VOID
230c2c66affSColin Finck FASTCALL
KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)231c2c66affSColin Finck KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,
232c2c66affSColin Finck IN PKINTERRUPT Interrupt)
233c2c66affSColin Finck {
234c2c66affSColin Finck KIRQL OldIrql, OldInterruptIrql = 0;
235c2c66affSColin Finck BOOLEAN Handled;
236c2c66affSColin Finck PLIST_ENTRY NextEntry, ListHead;
237c2c66affSColin Finck
238c2c66affSColin Finck /* Increase interrupt count */
239c2c66affSColin Finck KeGetCurrentPrcb()->InterruptCount++;
240c2c66affSColin Finck
241c2c66affSColin Finck /* Begin the interrupt, making sure it's not spurious */
242c2c66affSColin Finck if (HalBeginSystemInterrupt(Interrupt->Irql,
243c2c66affSColin Finck Interrupt->Vector,
244c2c66affSColin Finck &OldIrql))
245c2c66affSColin Finck {
246c2c66affSColin Finck /* Get list pointers */
247c2c66affSColin Finck ListHead = &Interrupt->InterruptListEntry;
248c2c66affSColin Finck NextEntry = ListHead; /* The head is an entry! */
249c2c66affSColin Finck while (TRUE)
250c2c66affSColin Finck {
251c2c66affSColin Finck /* Check if this interrupt's IRQL is higher than the current one */
252c2c66affSColin Finck if (Interrupt->SynchronizeIrql > Interrupt->Irql)
253c2c66affSColin Finck {
254c2c66affSColin Finck /* Raise to higher IRQL */
255c2c66affSColin Finck OldInterruptIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
256c2c66affSColin Finck }
257c2c66affSColin Finck
258c2c66affSColin Finck /* Acquire interrupt lock */
259c2c66affSColin Finck KxAcquireSpinLock(Interrupt->ActualLock);
260c2c66affSColin Finck
261c2c66affSColin Finck /* Call the ISR */
262c2c66affSColin Finck Handled = Interrupt->ServiceRoutine(Interrupt,
263c2c66affSColin Finck Interrupt->ServiceContext);
264c2c66affSColin Finck
265c2c66affSColin Finck /* Release interrupt lock */
266c2c66affSColin Finck KxReleaseSpinLock(Interrupt->ActualLock);
267c2c66affSColin Finck
268c2c66affSColin Finck /* Check if this interrupt's IRQL is higher than the current one */
269c2c66affSColin Finck if (Interrupt->SynchronizeIrql > Interrupt->Irql)
270c2c66affSColin Finck {
271c2c66affSColin Finck /* Lower the IRQL back */
272c2c66affSColin Finck ASSERT(OldInterruptIrql == Interrupt->Irql);
273c2c66affSColin Finck KfLowerIrql(OldInterruptIrql);
274c2c66affSColin Finck }
275c2c66affSColin Finck
276c2c66affSColin Finck /* Check if the interrupt got handled and it's level */
277c2c66affSColin Finck if ((Handled) && (Interrupt->Mode == LevelSensitive)) break;
278c2c66affSColin Finck
279c2c66affSColin Finck /* What's next? */
280c2c66affSColin Finck NextEntry = NextEntry->Flink;
281c2c66affSColin Finck
282c2c66affSColin Finck /* Is this the last one? */
283c2c66affSColin Finck if (NextEntry == ListHead)
284c2c66affSColin Finck {
285c2c66affSColin Finck /* Level should not have gotten here */
286c2c66affSColin Finck if (Interrupt->Mode == LevelSensitive) break;
287c2c66affSColin Finck
288c2c66affSColin Finck /* As for edge, we can only exit once nobody can handle the interrupt */
289c2c66affSColin Finck if (!Handled) break;
290c2c66affSColin Finck }
291c2c66affSColin Finck
292c2c66affSColin Finck /* Get the interrupt object for the next pass */
293c2c66affSColin Finck Interrupt = CONTAINING_RECORD(NextEntry, KINTERRUPT, InterruptListEntry);
294c2c66affSColin Finck }
295c2c66affSColin Finck
296c2c66affSColin Finck /* Now call the epilogue code */
297c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, FALSE);
298c2c66affSColin Finck }
299c2c66affSColin Finck else
300c2c66affSColin Finck {
301c2c66affSColin Finck /* Now call the epilogue code */
302c2c66affSColin Finck KiExitInterrupt(TrapFrame, OldIrql, TRUE);
303c2c66affSColin Finck }
304c2c66affSColin Finck }
305c2c66affSColin Finck
306c2c66affSColin Finck VOID
307c2c66affSColin Finck FASTCALL
KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)308c2c66affSColin Finck KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame,
309c2c66affSColin Finck IN PKINTERRUPT Interrupt)
310c2c66affSColin Finck {
311c2c66affSColin Finck /* Enter interrupt frame */
312c2c66affSColin Finck KiEnterInterruptTrap(TrapFrame);
313c2c66affSColin Finck
314c2c66affSColin Finck /* Call the correct dispatcher */
315c2c66affSColin Finck ((PKI_INTERRUPT_DISPATCH)Interrupt->DispatchAddress)(TrapFrame, Interrupt);
316c2c66affSColin Finck }
317c2c66affSColin Finck
318c2c66affSColin Finck
319c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
320c2c66affSColin Finck
321c2c66affSColin Finck /*
322c2c66affSColin Finck * @implemented
323c2c66affSColin Finck */
324c2c66affSColin Finck VOID
325c2c66affSColin Finck NTAPI
KeInitializeInterrupt(IN PKINTERRUPT Interrupt,IN PKSERVICE_ROUTINE ServiceRoutine,IN PVOID ServiceContext,IN PKSPIN_LOCK SpinLock,IN ULONG Vector,IN KIRQL Irql,IN KIRQL SynchronizeIrql,IN KINTERRUPT_MODE InterruptMode,IN BOOLEAN ShareVector,IN CHAR ProcessorNumber,IN BOOLEAN FloatingSave)326c2c66affSColin Finck KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
327c2c66affSColin Finck IN PKSERVICE_ROUTINE ServiceRoutine,
328c2c66affSColin Finck IN PVOID ServiceContext,
329c2c66affSColin Finck IN PKSPIN_LOCK SpinLock,
330c2c66affSColin Finck IN ULONG Vector,
331c2c66affSColin Finck IN KIRQL Irql,
332c2c66affSColin Finck IN KIRQL SynchronizeIrql,
333c2c66affSColin Finck IN KINTERRUPT_MODE InterruptMode,
334c2c66affSColin Finck IN BOOLEAN ShareVector,
335c2c66affSColin Finck IN CHAR ProcessorNumber,
336c2c66affSColin Finck IN BOOLEAN FloatingSave)
337c2c66affSColin Finck {
338c2c66affSColin Finck ULONG i;
339c2c66affSColin Finck PULONG DispatchCode = &Interrupt->DispatchCode[0], Patch = DispatchCode;
340c2c66affSColin Finck
341c2c66affSColin Finck /* Set the Interrupt Header */
342c2c66affSColin Finck Interrupt->Type = InterruptObject;
343c2c66affSColin Finck Interrupt->Size = sizeof(KINTERRUPT);
344c2c66affSColin Finck
345c2c66affSColin Finck /* Check if we got a spinlock */
346c2c66affSColin Finck if (SpinLock)
347c2c66affSColin Finck {
348c2c66affSColin Finck Interrupt->ActualLock = SpinLock;
349c2c66affSColin Finck }
350c2c66affSColin Finck else
351c2c66affSColin Finck {
352*2d442956SSerge Gautherie /* Use the built-in one */
353c2c66affSColin Finck KeInitializeSpinLock(&Interrupt->SpinLock);
354c2c66affSColin Finck Interrupt->ActualLock = &Interrupt->SpinLock;
355c2c66affSColin Finck }
356c2c66affSColin Finck
357c2c66affSColin Finck /* Set the other settings */
358c2c66affSColin Finck Interrupt->ServiceRoutine = ServiceRoutine;
359c2c66affSColin Finck Interrupt->ServiceContext = ServiceContext;
360c2c66affSColin Finck Interrupt->Vector = Vector;
361c2c66affSColin Finck Interrupt->Irql = Irql;
362c2c66affSColin Finck Interrupt->SynchronizeIrql = SynchronizeIrql;
363c2c66affSColin Finck Interrupt->Mode = InterruptMode;
364c2c66affSColin Finck Interrupt->ShareVector = ShareVector;
365c2c66affSColin Finck Interrupt->Number = ProcessorNumber;
366c2c66affSColin Finck Interrupt->FloatingSave = FloatingSave;
367c2c66affSColin Finck Interrupt->TickCount = MAXULONG;
368c2c66affSColin Finck Interrupt->DispatchCount = MAXULONG;
369c2c66affSColin Finck
370c2c66affSColin Finck /* Loop the template in memory */
371c2c66affSColin Finck for (i = 0; i < DISPATCH_LENGTH; i++)
372c2c66affSColin Finck {
373c2c66affSColin Finck /* Copy the dispatch code */
374c2c66affSColin Finck *DispatchCode++ = ((PULONG)KiInterruptTemplate)[i];
375c2c66affSColin Finck }
376c2c66affSColin Finck
377c2c66affSColin Finck /* Jump to the last 4 bytes */
378c2c66affSColin Finck Patch = (PULONG)((ULONG_PTR)Patch +
379c2c66affSColin Finck ((ULONG_PTR)&KiInterruptTemplateObject -
380c2c66affSColin Finck (ULONG_PTR)KiInterruptTemplate) - 4);
381c2c66affSColin Finck
382c2c66affSColin Finck /* Apply the patch */
383c2c66affSColin Finck *Patch = PtrToUlong(Interrupt);
384c2c66affSColin Finck
385c2c66affSColin Finck /* Disconnect it at first */
386c2c66affSColin Finck Interrupt->Connected = FALSE;
387c2c66affSColin Finck }
388c2c66affSColin Finck
389c2c66affSColin Finck /*
390c2c66affSColin Finck * @implemented
391c2c66affSColin Finck */
392c2c66affSColin Finck BOOLEAN
393c2c66affSColin Finck NTAPI
KeConnectInterrupt(IN PKINTERRUPT Interrupt)394c2c66affSColin Finck KeConnectInterrupt(IN PKINTERRUPT Interrupt)
395c2c66affSColin Finck {
396c2c66affSColin Finck BOOLEAN Connected, Error, Status;
397c2c66affSColin Finck KIRQL Irql, OldIrql;
398c2c66affSColin Finck UCHAR Number;
399c2c66affSColin Finck ULONG Vector;
400c2c66affSColin Finck DISPATCH_INFO Dispatch;
401c2c66affSColin Finck
402c2c66affSColin Finck /* Get data from interrupt */
403c2c66affSColin Finck Number = Interrupt->Number;
404c2c66affSColin Finck Vector = Interrupt->Vector;
405c2c66affSColin Finck Irql = Interrupt->Irql;
406c2c66affSColin Finck
407c2c66affSColin Finck /* Validate the settings */
408c2c66affSColin Finck if ((Irql > HIGH_LEVEL) ||
409c2c66affSColin Finck (Number >= KeNumberProcessors) ||
410c2c66affSColin Finck (Interrupt->SynchronizeIrql < Irql) ||
411c2c66affSColin Finck (Interrupt->FloatingSave))
412c2c66affSColin Finck {
413c2c66affSColin Finck return FALSE;
414c2c66affSColin Finck }
415c2c66affSColin Finck
416c2c66affSColin Finck /* Set defaults */
417c2c66affSColin Finck Connected = FALSE;
418c2c66affSColin Finck Error = FALSE;
419c2c66affSColin Finck
420c2c66affSColin Finck /* Set the system affinity and acquire the dispatcher lock */
421c2c66affSColin Finck KeSetSystemAffinityThread(1 << Number);
422c2c66affSColin Finck OldIrql = KiAcquireDispatcherLock();
423c2c66affSColin Finck
424c2c66affSColin Finck /* Check if it's already been connected */
425c2c66affSColin Finck if (!Interrupt->Connected)
426c2c66affSColin Finck {
427c2c66affSColin Finck /* Get vector dispatching information */
428c2c66affSColin Finck KiGetVectorDispatch(Vector, &Dispatch);
429c2c66affSColin Finck
430c2c66affSColin Finck /* Check if the vector is already connected */
431c2c66affSColin Finck if (Dispatch.Type == NoConnect)
432c2c66affSColin Finck {
433c2c66affSColin Finck /* Do the connection */
434c2c66affSColin Finck Interrupt->Connected = Connected = TRUE;
435c2c66affSColin Finck
436c2c66affSColin Finck /* Initialize the list */
437c2c66affSColin Finck InitializeListHead(&Interrupt->InterruptListEntry);
438c2c66affSColin Finck
439c2c66affSColin Finck /* Connect and enable the interrupt */
440c2c66affSColin Finck KiConnectVectorToInterrupt(Interrupt, NormalConnect);
441c2c66affSColin Finck Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
442c2c66affSColin Finck if (!Status) Error = TRUE;
443c2c66affSColin Finck }
444c2c66affSColin Finck else if ((Dispatch.Type != UnknownConnect) &&
445c2c66affSColin Finck (Interrupt->ShareVector) &&
446c2c66affSColin Finck (Dispatch.Interrupt->ShareVector) &&
447c2c66affSColin Finck (Dispatch.Interrupt->Mode == Interrupt->Mode))
448c2c66affSColin Finck {
449c2c66affSColin Finck /* The vector is shared and the interrupts are compatible */
450c2c66affSColin Finck Interrupt->Connected = Connected = TRUE;
451c2c66affSColin Finck
452c2c66affSColin Finck /*
453c2c66affSColin Finck * Verify the IRQL for chained connect,
454c2c66affSColin Finck */
455c2c66affSColin Finck #if defined(CONFIG_SMP)
456c2c66affSColin Finck ASSERT(Irql <= SYNCH_LEVEL);
457c2c66affSColin Finck #else
458c2c66affSColin Finck ASSERT(Irql <= (IPI_LEVEL - 2));
459c2c66affSColin Finck #endif
460c2c66affSColin Finck
461c2c66affSColin Finck /* Check if this is the first chain */
462c2c66affSColin Finck if (Dispatch.Type != ChainConnect)
463c2c66affSColin Finck {
464c2c66affSColin Finck /* This is not supported */
465c2c66affSColin Finck ASSERT(Dispatch.Interrupt->Mode != Latched);
466c2c66affSColin Finck
467c2c66affSColin Finck /* Setup the chainned handler */
468c2c66affSColin Finck KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
469c2c66affSColin Finck }
470c2c66affSColin Finck
471c2c66affSColin Finck /* Insert into the interrupt list */
472c2c66affSColin Finck InsertTailList(&Dispatch.Interrupt->InterruptListEntry,
473c2c66affSColin Finck &Interrupt->InterruptListEntry);
474c2c66affSColin Finck }
475c2c66affSColin Finck }
476c2c66affSColin Finck
477c2c66affSColin Finck /* Unlock the dispatcher and revert affinity */
478c2c66affSColin Finck KiReleaseDispatcherLock(OldIrql);
479c2c66affSColin Finck KeRevertToUserAffinityThread();
480c2c66affSColin Finck
481c2c66affSColin Finck /* Check if we failed while trying to connect */
482c2c66affSColin Finck if ((Connected) && (Error))
483c2c66affSColin Finck {
484c2c66affSColin Finck DPRINT1("HalEnableSystemInterrupt failed\n");
485c2c66affSColin Finck KeDisconnectInterrupt(Interrupt);
486c2c66affSColin Finck Connected = FALSE;
487c2c66affSColin Finck }
488c2c66affSColin Finck
489c2c66affSColin Finck /* Return to caller */
490c2c66affSColin Finck return Connected;
491c2c66affSColin Finck }
492c2c66affSColin Finck
493c2c66affSColin Finck /*
494c2c66affSColin Finck * @implemented
495c2c66affSColin Finck */
496c2c66affSColin Finck BOOLEAN
497c2c66affSColin Finck NTAPI
KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)498c2c66affSColin Finck KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
499c2c66affSColin Finck {
500c2c66affSColin Finck KIRQL OldIrql, Irql;
501c2c66affSColin Finck ULONG Vector;
502c2c66affSColin Finck DISPATCH_INFO Dispatch;
503c2c66affSColin Finck PKINTERRUPT NextInterrupt;
504c2c66affSColin Finck BOOLEAN State;
505c2c66affSColin Finck
506c2c66affSColin Finck /* Set the affinity */
507c2c66affSColin Finck KeSetSystemAffinityThread(1 << Interrupt->Number);
508c2c66affSColin Finck
509c2c66affSColin Finck /* Lock the dispatcher */
510c2c66affSColin Finck OldIrql = KiAcquireDispatcherLock();
511c2c66affSColin Finck
512c2c66affSColin Finck /* Check if it's actually connected */
513c2c66affSColin Finck State = Interrupt->Connected;
514c2c66affSColin Finck if (State)
515c2c66affSColin Finck {
516c2c66affSColin Finck /* Get the vector and IRQL */
517c2c66affSColin Finck Irql = Interrupt->Irql;
518c2c66affSColin Finck Vector = Interrupt->Vector;
519c2c66affSColin Finck
520c2c66affSColin Finck /* Get vector dispatch data */
521c2c66affSColin Finck KiGetVectorDispatch(Vector, &Dispatch);
522c2c66affSColin Finck
523c2c66affSColin Finck /* Check if it was chained */
524c2c66affSColin Finck if (Dispatch.Type == ChainConnect)
525c2c66affSColin Finck {
526c2c66affSColin Finck /* Check if the top-level interrupt is being removed */
527c2c66affSColin Finck #if defined(CONFIG_SMP)
528c2c66affSColin Finck ASSERT(Irql <= SYNCH_LEVEL);
529c2c66affSColin Finck #else
530c2c66affSColin Finck ASSERT(Irql <= (IPI_LEVEL - 2));
531c2c66affSColin Finck #endif
532c2c66affSColin Finck if (Interrupt == Dispatch.Interrupt)
533c2c66affSColin Finck {
534c2c66affSColin Finck /* Get the next one */
535c2c66affSColin Finck Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt->
536c2c66affSColin Finck InterruptListEntry.Flink,
537c2c66affSColin Finck KINTERRUPT,
538c2c66affSColin Finck InterruptListEntry);
539c2c66affSColin Finck
540c2c66affSColin Finck /* Reconnect it */
541c2c66affSColin Finck KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
542c2c66affSColin Finck }
543c2c66affSColin Finck
544c2c66affSColin Finck /* Remove it */
545c2c66affSColin Finck RemoveEntryList(&Interrupt->InterruptListEntry);
546c2c66affSColin Finck
547c2c66affSColin Finck /* Get the next one */
548c2c66affSColin Finck NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt->
549c2c66affSColin Finck InterruptListEntry.Flink,
550c2c66affSColin Finck KINTERRUPT,
551c2c66affSColin Finck InterruptListEntry);
552c2c66affSColin Finck
553c2c66affSColin Finck /* Check if this is the only one left */
554c2c66affSColin Finck if (Dispatch.Interrupt == NextInterrupt)
555c2c66affSColin Finck {
556c2c66affSColin Finck /* Connect it in non-chained mode */
557c2c66affSColin Finck KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect);
558c2c66affSColin Finck }
559c2c66affSColin Finck }
560c2c66affSColin Finck else
561c2c66affSColin Finck {
562c2c66affSColin Finck /* Only one left, disable and remove it */
563c2c66affSColin Finck HalDisableSystemInterrupt(Interrupt->Vector, Irql);
564c2c66affSColin Finck KiConnectVectorToInterrupt(Interrupt, NoConnect);
565c2c66affSColin Finck }
566c2c66affSColin Finck
567c2c66affSColin Finck /* Disconnect it */
568c2c66affSColin Finck Interrupt->Connected = FALSE;
569c2c66affSColin Finck }
570c2c66affSColin Finck
571c2c66affSColin Finck /* Unlock the dispatcher and revert affinity */
572c2c66affSColin Finck KiReleaseDispatcherLock(OldIrql);
573c2c66affSColin Finck KeRevertToUserAffinityThread();
574c2c66affSColin Finck
575c2c66affSColin Finck /* Return to caller */
576c2c66affSColin Finck return State;
577c2c66affSColin Finck }
578c2c66affSColin Finck
579c2c66affSColin Finck /*
580c2c66affSColin Finck * @implemented
581c2c66affSColin Finck */
582c2c66affSColin Finck BOOLEAN
583c2c66affSColin Finck NTAPI
KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,IN PVOID SynchronizeContext OPTIONAL)584c2c66affSColin Finck KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,
585c2c66affSColin Finck IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
586c2c66affSColin Finck IN PVOID SynchronizeContext OPTIONAL)
587c2c66affSColin Finck {
588c2c66affSColin Finck BOOLEAN Success;
589c2c66affSColin Finck KIRQL OldIrql;
590c2c66affSColin Finck
591c2c66affSColin Finck /* Raise IRQL */
592c2c66affSColin Finck KeRaiseIrql(Interrupt->SynchronizeIrql,
593c2c66affSColin Finck &OldIrql);
594c2c66affSColin Finck
595c2c66affSColin Finck /* Acquire interrupt spinlock */
596c2c66affSColin Finck KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
597c2c66affSColin Finck
598c2c66affSColin Finck /* Call the routine */
599c2c66affSColin Finck Success = SynchronizeRoutine(SynchronizeContext);
600c2c66affSColin Finck
601c2c66affSColin Finck /* Release lock */
602c2c66affSColin Finck KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
603c2c66affSColin Finck
604c2c66affSColin Finck /* Lower IRQL */
605c2c66affSColin Finck KeLowerIrql(OldIrql);
606c2c66affSColin Finck
607c2c66affSColin Finck /* Return status */
608c2c66affSColin Finck return Success;
609c2c66affSColin Finck }
610c2c66affSColin Finck
611c2c66affSColin Finck /* EOF */
612