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