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
;
80 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector
);
82 /* Convert the Mask */
83 ProcessorEnableMask
&= ((1 << KeNumberProcessors
) - 1);
85 /* Make sure at least one CPU is on it */
86 if (!ProcessorEnableMask
) return STATUS_INVALID_PARAMETER
;
88 /* Determine the allocation */
89 for (i
= 0, count
= 0; i
< KeNumberProcessors
; i
++)
91 if (ProcessorEnableMask
& (1 << i
)) count
++;
94 /* Allocate the array of I/O Interrupts */
95 IoInterrupt
= ExAllocatePoolWithTag(NonPagedPool
,
96 (count
- 1)* sizeof(KINTERRUPT
) +
99 if (!IoInterrupt
) return(STATUS_INSUFFICIENT_RESOURCES
);
101 /* Select which Spinlock to use */
104 SpinLockUsed
= SpinLock
;
108 SpinLockUsed
= &IoInterrupt
->SpinLock
;
111 /* We first start with a built-in Interrupt inside the I/O Structure */
112 *InterruptObject
= &IoInterrupt
->FirstInterrupt
;
113 Interrupt
= (PKINTERRUPT
)(IoInterrupt
+ 1);
116 /* Start with a fresh structure */
117 RtlZeroMemory(IoInterrupt
, sizeof(IO_INTERRUPT
));
119 /* Now create all the interrupts */
120 for (i
= 0; i
< KeNumberProcessors
; i
++)
122 /* Check if it's enabled for this CPU */
123 if (ProcessorEnableMask
& (1 << i
))
125 /* Check which one we will use */
126 InterruptUsed
= FirstRun
? &IoInterrupt
->FirstInterrupt
: Interrupt
;
129 KeInitializeInterrupt(InterruptUsed
,
142 if (!KeConnectInterrupt(InterruptUsed
))
144 /* Check how far we got */
147 /* We failed early so just free this */
148 ExFreePool(IoInterrupt
);
152 /* Far enough, so disconnect everything */
153 IoDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
155 return STATUS_INVALID_PARAMETER
;
158 /* Now we've used up our First Run */
165 /* Move on to the next one */
166 IoInterrupt
->Interrupt
[i
] = Interrupt
++;
172 return STATUS_SUCCESS
;
176 * FUNCTION: Releases a drivers isr
178 * InterruptObject = isr to release
184 IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
188 PIO_INTERRUPT IoInterrupt
;
192 /* Get the I/O Interrupt */
193 IoInterrupt
= CONTAINING_RECORD(InterruptObject
,
197 /* Disconnect the first one */
198 KeDisconnectInterrupt(&IoInterrupt
->FirstInterrupt
);
200 /* Now disconnect the others */
201 for (i
= 0; i
< KeNumberProcessors
; i
++)
203 if (IoInterrupt
->Interrupt
[i
])
205 KeDisconnectInterrupt(&InterruptObject
[i
]);
209 /* Free the I/O Interrupt */
210 ExFreePool(IoInterrupt
);