xref: /reactos/ntoskrnl/io/iomgr/irq.c (revision cce399e7)
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                 return STATUS_INVALID_PARAMETER;
116             }
117 
118             /* Now we've used up our First Run */
119             if (FirstRun)
120             {
121                 FirstRun = FALSE;
122             }
123             else
124             {
125                 /* Move on to the next one */
126                 IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++;
127             }
128         }
129     }
130 
131     /* Return Success */
132     return STATUS_SUCCESS;
133 }
134 
135 /*
136  * @implemented
137  */
138 VOID
139 NTAPI
140 IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
141 {
142     LONG i;
143     PIO_INTERRUPT IoInterrupt;
144     PAGED_CODE();
145 
146     /* Get the I/O Interrupt */
147     IoInterrupt = CONTAINING_RECORD(InterruptObject,
148                                     IO_INTERRUPT,
149                                     FirstInterrupt);
150 
151     /* Disconnect the first one */
152     KeDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
153 
154     /* Now disconnect the others */
155     for (i = 0; i < KeNumberProcessors; i++)
156     {
157         /* Make sure one was registered */
158         if (IoInterrupt->Interrupt[i])
159         {
160             /* Disconnect it */
161             KeDisconnectInterrupt(&InterruptObject[i]);
162         }
163     }
164 
165     /* Free the I/O Interrupt */
166     ExFreePool(IoInterrupt); // ExFreePoolWithTag(IoInterrupt, TAG_KINTERRUPT);
167 }
168 
169 NTSTATUS
170 IopConnectInterruptExFullySpecific(
171     _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
172 {
173     NTSTATUS Status;
174     PAGED_CODE();
175 
176     /* Fallback to standard IoConnectInterrupt */
177     Status = IoConnectInterrupt(Parameters->FullySpecified.InterruptObject,
178                                 Parameters->FullySpecified.ServiceRoutine,
179                                 Parameters->FullySpecified.ServiceContext,
180                                 Parameters->FullySpecified.SpinLock,
181                                 Parameters->FullySpecified.Vector,
182                                 Parameters->FullySpecified.Irql,
183                                 Parameters->FullySpecified.SynchronizeIrql,
184                                 Parameters->FullySpecified.InterruptMode,
185                                 Parameters->FullySpecified.ShareVector,
186                                 Parameters->FullySpecified.ProcessorEnableMask,
187                                 Parameters->FullySpecified.FloatingSave);
188     DPRINT("IopConnectInterruptEx_FullySpecific: has failed with status %X", Status);
189     return Status;
190 }
191 
192 NTSTATUS
193 NTAPI
194 IoConnectInterruptEx(
195     _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
196 {
197     PAGED_CODE();
198     switch (Parameters->Version)
199     {
200         case CONNECT_FULLY_SPECIFIED:
201             return IopConnectInterruptExFullySpecific(Parameters);
202         case CONNECT_FULLY_SPECIFIED_GROUP:
203             //TODO: We don't do anything for the group type
204             return IopConnectInterruptExFullySpecific(Parameters);
205         case CONNECT_MESSAGE_BASED:
206             DPRINT1("FIXME: Message based interrupts are UNIMPLEMENTED\n");
207             break;
208         case CONNECT_LINE_BASED:
209             DPRINT1("FIXME: Line based interrupts are UNIMPLEMENTED\n");
210             break;
211     }
212     return STATUS_SUCCESS;
213 }
214 
215 VOID
216 NTAPI
217 IoDisconnectInterruptEx(
218     _In_ PIO_DISCONNECT_INTERRUPT_PARAMETERS Parameters)
219 {
220     PAGED_CODE();
221 
222     //FIXME: This eventually will need to handle more cases
223     if (Parameters->ConnectionContext.InterruptObject)
224         IoDisconnectInterrupt(Parameters->ConnectionContext.InterruptObject);
225 }
226 
227 /* EOF */
228