Of course, I forgot to commit the new file in revision 22049...
[reactos.git] / reactos / ntoskrnl / io / irq.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/irq.c
6 * PURPOSE: IRQ handling
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* TYPES ********************************************************************/
18 typedef struct _IO_INTERRUPT
19 {
20 KINTERRUPT FirstInterrupt;
21 PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS];
22 KSPIN_LOCK SpinLock;
23 } IO_INTERRUPT, *PIO_INTERRUPT;
24
25 /* FUNCTIONS *****************************************************************/
26
27 /*
28 * FUNCTION: Registers a driver's isr to be called when its device interrupts
29 * ARGUMENTS:
30 * InterruptObject (OUT) = Points to the interrupt object created on
31 * return
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
44 * isrs
45 * InterruptMode = Specifies if the interrupt is LevelSensitive or
46 * Latched
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
51 * RETURNS: Status
52 * IRQL: PASSIVE_LEVEL
53 *
54 * @implemented
55 */
56 NTSTATUS
57 STDCALL
58 IoConnectInterrupt(PKINTERRUPT* InterruptObject,
59 PKSERVICE_ROUTINE ServiceRoutine,
60 PVOID ServiceContext,
61 PKSPIN_LOCK SpinLock,
62 ULONG Vector,
63 KIRQL Irql,
64 KIRQL SynchronizeIrql,
65 KINTERRUPT_MODE InterruptMode,
66 BOOLEAN ShareVector,
67 KAFFINITY ProcessorEnableMask,
68 BOOLEAN FloatingSave)
69 {
70 PKINTERRUPT Interrupt;
71 PKINTERRUPT InterruptUsed;
72 PIO_INTERRUPT IoInterrupt;
73 PKSPIN_LOCK SpinLockUsed;
74 BOOLEAN FirstRun = TRUE;
75 ULONG count;
76 LONG i;
77
78 PAGED_CODE();
79
80 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector);
81
82 /* Convert the Mask */
83 ProcessorEnableMask &= ((1 << KeNumberProcessors) - 1);
84
85 /* Make sure at least one CPU is on it */
86 if (!ProcessorEnableMask) return STATUS_INVALID_PARAMETER;
87
88 /* Determine the allocation */
89 for (i = 0, count = 0; i < KeNumberProcessors; i++)
90 {
91 if (ProcessorEnableMask & (1 << i)) count++;
92 }
93
94 /* Allocate the array of I/O Interrupts */
95 IoInterrupt = ExAllocatePoolWithTag(NonPagedPool,
96 (count - 1)* sizeof(KINTERRUPT) +
97 sizeof(IO_INTERRUPT),
98 TAG_KINTERRUPT);
99 if (!IoInterrupt) return(STATUS_INSUFFICIENT_RESOURCES);
100
101 /* Select which Spinlock to use */
102 if (SpinLock)
103 {
104 SpinLockUsed = SpinLock;
105 }
106 else
107 {
108 SpinLockUsed = &IoInterrupt->SpinLock;
109 }
110
111 /* We first start with a built-in Interrupt inside the I/O Structure */
112 *InterruptObject = &IoInterrupt->FirstInterrupt;
113 Interrupt = (PKINTERRUPT)(IoInterrupt + 1);
114 FirstRun = TRUE;
115
116 /* Start with a fresh structure */
117 RtlZeroMemory(IoInterrupt, sizeof(IO_INTERRUPT));
118
119 /* Now create all the interrupts */
120 for (i = 0; i < KeNumberProcessors; i++)
121 {
122 /* Check if it's enabled for this CPU */
123 if (ProcessorEnableMask & (1 << i))
124 {
125 /* Check which one we will use */
126 InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt;
127
128 /* Initialize it */
129 KeInitializeInterrupt(InterruptUsed,
130 ServiceRoutine,
131 ServiceContext,
132 SpinLockUsed,
133 Vector,
134 Irql,
135 SynchronizeIrql,
136 InterruptMode,
137 ShareVector,
138 i,
139 FloatingSave);
140
141 /* Connect it */
142 if (!KeConnectInterrupt(InterruptUsed))
143 {
144 /* Check how far we got */
145 if (FirstRun)
146 {
147 /* We failed early so just free this */
148 ExFreePool(IoInterrupt);
149 }
150 else
151 {
152 /* Far enough, so disconnect everything */
153 IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
154 }
155 return STATUS_INVALID_PARAMETER;
156 }
157
158 /* Now we've used up our First Run */
159 if (FirstRun)
160 {
161 FirstRun = FALSE;
162 }
163 else
164 {
165 /* Move on to the next one */
166 IoInterrupt->Interrupt[i] = Interrupt++;
167 }
168 }
169 }
170
171 /* Return Success */
172 return STATUS_SUCCESS;
173 }
174
175 /*
176 * FUNCTION: Releases a drivers isr
177 * ARGUMENTS:
178 * InterruptObject = isr to release
179 *
180 * @implemented
181 */
182 VOID
183 STDCALL
184 IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
185
186 {
187 LONG i;
188 PIO_INTERRUPT IoInterrupt;
189
190 PAGED_CODE();
191
192 /* Get the I/O Interrupt */
193 IoInterrupt = CONTAINING_RECORD(InterruptObject,
194 IO_INTERRUPT,
195 FirstInterrupt);
196
197 /* Disconnect the first one */
198 KeDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
199
200 /* Now disconnect the others */
201 for (i = 0; i < KeNumberProcessors; i++)
202 {
203 if (IoInterrupt->Interrupt[i])
204 {
205 KeDisconnectInterrupt(&InterruptObject[i]);
206 }
207 }
208
209 /* Free the I/O Interrupt */
210 ExFreePool(IoInterrupt);
211 }
212
213 /* EOF */