xref: /reactos/ntoskrnl/io/iomgr/irq.c (revision cadfdc55)
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
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
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
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
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
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