3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/irq.c
6 * PURPOSE: IRQ handling
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* TYPES ********************************************************************/
18 typedef struct _IO_INTERRUPT
20 KINTERRUPT FirstInterrupt
;
21 PKINTERRUPT Interrupt
[MAXIMUM_PROCESSORS
];
23 } IO_INTERRUPT
, *PIO_INTERRUPT
;
25 /* FUNCTIONS *****************************************************************/
28 * FUNCTION: Registers a driver's isr to be called when its device interrupts
30 * InterruptObject (OUT) = Points to the interrupt object created on
32 * ServiceRoutine = Routine to be called when the device interrupts
33 * ServiceContext = Parameter to be passed to ServiceRoutine
34 * SpinLock = Initalized spinlock that will be used to synchronize
35 * access between the isr and other driver routines. This is
36 * required if the isr handles more than one vector or the
37 * driver has more than one isr
38 * Vector = Interrupt vector to allocate
39 * (returned from HalGetInterruptVector)
40 * Irql = DIRQL returned from HalGetInterruptVector
41 * SynchronizeIrql = DIRQL at which the isr will execute. This must
42 * be the highest of all the DIRQLs returned from
43 * HalGetInterruptVector if the driver has multiple
45 * InterruptMode = Specifies if the interrupt is LevelSensitive or
47 * ShareVector = Specifies if the vector can be shared
48 * ProcessorEnableMask = Processors on the isr can run
49 * FloatingSave = TRUE if the floating point stack should be saved when
50 * the isr runs. Must be false for x86 drivers
58 IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
59 PKSERVICE_ROUTINE ServiceRoutine
,
64 KIRQL SynchronizeIrql
,
65 KINTERRUPT_MODE InterruptMode
,
67 KAFFINITY ProcessorEnableMask
,
70 PKINTERRUPT Interrupt
;
71 PKINTERRUPT InterruptUsed
;
72 PIO_INTERRUPT IoInterrupt
;
73 PKSPIN_LOCK SpinLockUsed
;
74 BOOLEAN FirstRun
= TRUE
;
79 DPRINT1("IoConnectInterrupt(Vector %x)\n",Vector
);
81 /* Convert the Mask */
82 ProcessorEnableMask
&= ((1 << KeNumberProcessors
) - 1);
84 /* Make sure at least one CPU is on it */
85 if (!ProcessorEnableMask
) return STATUS_INVALID_PARAMETER
;
87 /* Determine the allocation */
88 for (i
= 0, count
= 0; i
< KeNumberProcessors
; i
++)
90 if (ProcessorEnableMask
& (1 << i
)) count
++;
93 /* Allocate the array of I/O Interrupts */
94 IoInterrupt
= ExAllocatePoolWithTag(NonPagedPool
,
95 (count
- 1)* sizeof(KINTERRUPT
) +
98 if (!IoInterrupt
) return(STATUS_INSUFFICIENT_RESOURCES
);
100 /* Select which Spinlock to use */
103 SpinLockUsed
= SpinLock
;
107 SpinLockUsed
= &IoInterrupt
->SpinLock
;
110 /* We first start with a built-in Interrupt inside the I/O Structure */
111 *InterruptObject
= &IoInterrupt
->FirstInterrupt
;
112 Interrupt
= (PKINTERRUPT
)(IoInterrupt
+ 1);
115 /* Start with a fresh structure */
116 RtlZeroMemory(IoInterrupt
, sizeof(IO_INTERRUPT
));
118 /* Now create all the interrupts */
119 for (i
= 0; i
< KeNumberProcessors
; i
++)
121 /* Check if it's enabled for this CPU */
122 if (ProcessorEnableMask
& (1 << i
))
124 /* Check which one we will use */
125 InterruptUsed
= FirstRun
? &IoInterrupt
->FirstInterrupt
: Interrupt
;
128 KeInitializeInterrupt(InterruptUsed
,
141 if (!KeConnectInterrupt(InterruptUsed
))
143 /* Check how far we got */
146 /* We failed early so just free this */
147 ExFreePool(IoInterrupt
);
151 /* Far enough, so disconnect everything */
152 IoDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
154 return STATUS_INVALID_PARAMETER
;
157 /* Now we've used up our First Run */
164 /* Move on to the next one */
165 IoInterrupt
->Interrupt
[i
] = Interrupt
++;
171 return STATUS_SUCCESS
;
175 * FUNCTION: Releases a drivers isr
177 * InterruptObject = isr to release
183 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
187 PIO_INTERRUPT IoInterrupt
;
191 /* Get the I/O Interrupt */
192 IoInterrupt
= CONTAINING_RECORD(InterruptObject
,
196 /* Disconnect the first one */
197 KeDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
199 /* Now disconnect the others */
200 for (i
= 0; i
< KeNumberProcessors
; i
++)
202 if (IoInterrupt
->Interrupt
[i
])
204 KeDisconnectInterrupt(&InterruptObject
[i
]);
208 /* Free the I/O Interrupt */
209 ExFreePool(IoInterrupt
);