xref: /reactos/ntoskrnl/io/iomgr/irq.c (revision 1734f297)
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 /* EOF */
170