1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/irq.c
5 * PURPOSE: I/O Wrappers (called Completion Ports) for Kernel Queues
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 /*
19 * @implemented
20 */
21 NTSTATUS
22 NTAPI
IoConnectInterrupt(OUT PKINTERRUPT * InterruptObject,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 KAFFINITY ProcessorEnableMask,IN BOOLEAN FloatingSave)23 IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject,
24 IN PKSERVICE_ROUTINE ServiceRoutine,
25 IN PVOID ServiceContext,
26 IN PKSPIN_LOCK SpinLock,
27 IN ULONG Vector,
28 IN KIRQL Irql,
29 IN KIRQL SynchronizeIrql,
30 IN KINTERRUPT_MODE InterruptMode,
31 IN BOOLEAN ShareVector,
32 IN KAFFINITY ProcessorEnableMask,
33 IN BOOLEAN FloatingSave)
34 {
35 PKINTERRUPT Interrupt;
36 PKINTERRUPT InterruptUsed;
37 PIO_INTERRUPT IoInterrupt;
38 BOOLEAN FirstRun;
39 CCHAR Count = 0;
40 KAFFINITY Affinity;
41
42 PAGED_CODE();
43
44 /* Assume failure */
45 *InterruptObject = NULL;
46
47 /* Get the affinity */
48 Affinity = ProcessorEnableMask & KeActiveProcessors;
49 while (Affinity)
50 {
51 /* Increase count */
52 if (Affinity & 1) Count++;
53 Affinity >>= 1;
54 }
55
56 /* Make sure we have a valid CPU count */
57 if (!Count) return STATUS_INVALID_PARAMETER;
58
59 /* Allocate the array of I/O interrupts */
60 IoInterrupt = ExAllocatePoolZero(NonPagedPool,
61 (Count - 1) * sizeof(KINTERRUPT) +
62 sizeof(IO_INTERRUPT),
63 TAG_KINTERRUPT);
64 if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES;
65
66 /* Use the structure's spinlock, if none was provided */
67 if (!SpinLock)
68 {
69 SpinLock = &IoInterrupt->SpinLock;
70 KeInitializeSpinLock(SpinLock);
71 }
72
73 /* We first start with a built-in interrupt inside the I/O structure */
74 Interrupt = (PKINTERRUPT)(IoInterrupt + 1);
75 FirstRun = TRUE;
76
77 /* Now create all the interrupts */
78 Affinity = ProcessorEnableMask & KeActiveProcessors;
79 for (Count = 0; Affinity; Count++, Affinity >>= 1)
80 {
81 /* Check if it's enabled for this CPU */
82 if (!(Affinity & 1))
83 continue;
84
85 /* Check which one we will use */
86 InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt;
87
88 /* Initialize it */
89 KeInitializeInterrupt(InterruptUsed,
90 ServiceRoutine,
91 ServiceContext,
92 SpinLock,
93 Vector,
94 Irql,
95 SynchronizeIrql,
96 InterruptMode,
97 ShareVector,
98 Count,
99 FloatingSave);
100
101 /* Connect it */
102 if (!KeConnectInterrupt(InterruptUsed))
103 {
104 /* Check how far we got */
105 if (FirstRun)
106 {
107 /* We failed early so just free this */
108 ExFreePoolWithTag(IoInterrupt, TAG_KINTERRUPT);
109 }
110 else
111 {
112 /* Far enough, so disconnect everything */
113 IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
114 }
115
116 /* And fail */
117 return STATUS_INVALID_PARAMETER;
118 }
119
120 /* Now we've used up our First Run */
121 if (FirstRun)
122 {
123 FirstRun = FALSE;
124 }
125 else
126 {
127 /* Move on to the next one */
128 IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++;
129 }
130 }
131
132 /* Return success */
133 *InterruptObject = &IoInterrupt->FirstInterrupt;
134 return STATUS_SUCCESS;
135 }
136
137 /*
138 * @implemented
139 */
140 VOID
141 NTAPI
IoDisconnectInterrupt(PKINTERRUPT InterruptObject)142 IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
143 {
144 PIO_INTERRUPT IoInterrupt;
145 ULONG i;
146
147 PAGED_CODE();
148
149 /* Get the I/O interrupt */
150 IoInterrupt = CONTAINING_RECORD(InterruptObject,
151 IO_INTERRUPT,
152 FirstInterrupt);
153
154 /* Disconnect the first one */
155 KeDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
156
157 /* Now disconnect the others */
158 for (i = 0; i < KeNumberProcessors; i++)
159 {
160 /* Make sure one was registered */
161 if (!IoInterrupt->Interrupt[i])
162 continue;
163
164 /* Disconnect it */
165 KeDisconnectInterrupt(IoInterrupt->Interrupt[i]);
166 }
167
168 /* Free the I/O interrupt */
169 ExFreePoolWithTag(IoInterrupt, TAG_KINTERRUPT);
170 }
171
172 NTSTATUS
IopConnectInterruptExFullySpecific(_Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)173 IopConnectInterruptExFullySpecific(
174 _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
175 {
176 NTSTATUS Status;
177
178 PAGED_CODE();
179
180 /* Fallback to standard IoConnectInterrupt */
181 Status = IoConnectInterrupt(Parameters->FullySpecified.InterruptObject,
182 Parameters->FullySpecified.ServiceRoutine,
183 Parameters->FullySpecified.ServiceContext,
184 Parameters->FullySpecified.SpinLock,
185 Parameters->FullySpecified.Vector,
186 Parameters->FullySpecified.Irql,
187 Parameters->FullySpecified.SynchronizeIrql,
188 Parameters->FullySpecified.InterruptMode,
189 Parameters->FullySpecified.ShareVector,
190 Parameters->FullySpecified.ProcessorEnableMask,
191 Parameters->FullySpecified.FloatingSave);
192 DPRINT("IopConnectInterruptEx_FullySpecific: has failed with status %X", Status);
193 return Status;
194 }
195
196 NTSTATUS
197 NTAPI
IoConnectInterruptEx(_Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)198 IoConnectInterruptEx(
199 _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
200 {
201 PAGED_CODE();
202
203 switch (Parameters->Version)
204 {
205 case CONNECT_FULLY_SPECIFIED:
206 return IopConnectInterruptExFullySpecific(Parameters);
207 case CONNECT_FULLY_SPECIFIED_GROUP:
208 //TODO: We don't do anything for the group type
209 return IopConnectInterruptExFullySpecific(Parameters);
210 case CONNECT_MESSAGE_BASED:
211 DPRINT1("FIXME: Message based interrupts are UNIMPLEMENTED\n");
212 break;
213 case CONNECT_LINE_BASED:
214 DPRINT1("FIXME: Line based interrupts are UNIMPLEMENTED\n");
215 break;
216 }
217
218 return STATUS_SUCCESS;
219 }
220
221 VOID
222 NTAPI
IoDisconnectInterruptEx(_In_ PIO_DISCONNECT_INTERRUPT_PARAMETERS Parameters)223 IoDisconnectInterruptEx(
224 _In_ PIO_DISCONNECT_INTERRUPT_PARAMETERS Parameters)
225 {
226 PAGED_CODE();
227
228 //FIXME: This eventually will need to handle more cases
229 if (Parameters->ConnectionContext.InterruptObject)
230 IoDisconnectInterrupt(Parameters->ConnectionContext.InterruptObject);
231 }
232
233 /* EOF */
234