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