2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/irq.c
5 * PURPOSE: I/O Wrappers (called Completion Ports) for Kernel Queues
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* FUNCTIONS *****************************************************************/
22 IoConnectInterrupt(OUT PKINTERRUPT
*InterruptObject
,
23 IN PKSERVICE_ROUTINE ServiceRoutine
,
24 IN PVOID ServiceContext
,
25 IN PKSPIN_LOCK SpinLock
,
28 IN KIRQL SynchronizeIrql
,
29 IN KINTERRUPT_MODE InterruptMode
,
30 IN BOOLEAN ShareVector
,
31 IN KAFFINITY ProcessorEnableMask
,
32 IN BOOLEAN FloatingSave
)
34 PKINTERRUPT Interrupt
;
35 PKINTERRUPT InterruptUsed
;
36 PIO_INTERRUPT IoInterrupt
;
37 PKSPIN_LOCK SpinLockUsed
;
44 *InterruptObject
= NULL
;
46 /* Get the affinity */
47 Affinity
= ProcessorEnableMask
& KeActiveProcessors
;
51 if (Affinity
& 1) Count
++;
55 /* Make sure we have a valid CPU count */
56 if (!Count
) return STATUS_INVALID_PARAMETER
;
58 /* Allocate the array of I/O Interrupts */
59 IoInterrupt
= ExAllocatePoolWithTag(NonPagedPool
,
60 (Count
- 1) * sizeof(KINTERRUPT
) +
63 if (!IoInterrupt
) return STATUS_INSUFFICIENT_RESOURCES
;
65 /* Select which Spinlock to use */
66 SpinLockUsed
= SpinLock
? SpinLock
: &IoInterrupt
->SpinLock
;
68 /* We first start with a built-in Interrupt inside the I/O Structure */
69 *InterruptObject
= &IoInterrupt
->FirstInterrupt
;
70 Interrupt
= (PKINTERRUPT
)(IoInterrupt
+ 1);
73 /* Start with a fresh structure */
74 RtlZeroMemory(IoInterrupt
, sizeof(IO_INTERRUPT
));
76 /* Now create all the interrupts */
77 Affinity
= ProcessorEnableMask
& KeActiveProcessors
;
78 for (Count
= 0; Affinity
; Count
++, Affinity
>>= 1)
80 /* Check if it's enabled for this CPU */
83 /* Check which one we will use */
84 InterruptUsed
= FirstRun
? &IoInterrupt
->FirstInterrupt
: Interrupt
;
87 KeInitializeInterrupt(InterruptUsed
,
100 if (!KeConnectInterrupt(InterruptUsed
))
102 /* Check how far we got */
105 /* We failed early so just free this */
106 ExFreePool(IoInterrupt
);
110 /* Far enough, so disconnect everything */
111 IoDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
115 return STATUS_INVALID_PARAMETER
;
118 /* Now we've used up our First Run */
125 /* Move on to the next one */
126 IoInterrupt
->Interrupt
[(UCHAR
)Count
] = Interrupt
++;
132 return STATUS_SUCCESS
;
140 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
143 PIO_INTERRUPT IoInterrupt
;
146 /* Get the I/O Interrupt */
147 IoInterrupt
= CONTAINING_RECORD(InterruptObject
,
151 /* Disconnect the first one */
152 KeDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
154 /* Now disconnect the others */
155 for (i
= 0; i
< KeNumberProcessors
; i
++)
157 /* Make sure one was registered */
158 if (IoInterrupt
->Interrupt
[i
])
161 KeDisconnectInterrupt(&InterruptObject
[i
]);
165 /* Free the I/O Interrupt */
166 ExFreePool(IoInterrupt
);