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