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