Fixed irq problems.
[reactos.git] / reactos / hal / halx86 / irql.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/hal/x86/irql.c
5 * PURPOSE: Implements IRQLs
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <internal/ke.h>
13 #include <internal/ps.h>
14 #include <ntos/minmax.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 #define NR_IRQS (16)
22 #define IRQ_BASE (0x40)
23
24 /*
25 * PURPOSE: Current irq level
26 */
27 static KIRQL CurrentIrql = HIGH_LEVEL;
28
29 extern IMPORTED ULONG DpcQueueSize;
30
31 static ULONG HalpPendingInterruptCount[NR_IRQS];
32
33 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
34 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
35
36 VOID STDCALL
37 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
38
39 /* FUNCTIONS ****************************************************************/
40
41 KIRQL STDCALL KeGetCurrentIrql (VOID)
42 /*
43 * PURPOSE: Returns the current irq level
44 * RETURNS: The current irq level
45 */
46 {
47 return(CurrentIrql);
48 }
49
50 VOID HalpInitPICs(VOID)
51 {
52 memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
53
54 /* Initialization sequence */
55 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11);
56 WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11);
57 /* Start of hardware irqs (0x24) */
58 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x40);
59 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x48);
60 /* 8259-1 is master */
61 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4);
62 /* 8259-2 is slave */
63 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
64 /* 8086 mode */
65 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
66 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);
67 /* Enable all interrupts from PICs */
68 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x0);
69 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x0);
70
71 /* We can now enable interrupts */
72 __asm__ __volatile__ ("sti\n\t");
73 }
74
75 VOID STATIC
76 HalpExecuteIrqs(KIRQL NewIrql)
77 {
78 ULONG IrqLimit, i;
79
80 IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
81
82 /*
83 * For each irq if there have been any deferred interrupts then now
84 * dispatch them.
85 */
86 for (i = 0; i < IrqLimit; i++)
87 {
88 while (HalpPendingInterruptCount[i] > 0)
89 {
90 /*
91 * For each deferred interrupt execute all the handlers at DIRQL.
92 */
93 CurrentIrql = IRQ_TO_DIRQL(i);
94 KiInterruptDispatch2(i, NewIrql);
95 HalpPendingInterruptCount[i]--;
96 }
97 }
98 }
99
100 VOID STATIC
101 HalpLowerIrql(KIRQL NewIrql)
102 {
103 if (NewIrql > PROFILE_LEVEL)
104 {
105 CurrentIrql = NewIrql;
106 return;
107 }
108 HalpExecuteIrqs(NewIrql);
109 if (NewIrql >= DISPATCH_LEVEL)
110 {
111 CurrentIrql = NewIrql;
112 return;
113 }
114 CurrentIrql = DISPATCH_LEVEL;
115 if (DpcQueueSize > 0)
116 {
117 KiDispatchInterrupt();
118 }
119 if (NewIrql == APC_LEVEL)
120 {
121 CurrentIrql = NewIrql;
122 return;
123 }
124 CurrentIrql = APC_LEVEL;
125 if (KeGetCurrentThread() != NULL &&
126 KeGetCurrentThread()->ApcState.KernelApcPending)
127 {
128 KiDeliverApc(0, 0, 0);
129 }
130 CurrentIrql = PASSIVE_LEVEL;
131 }
132
133 /**********************************************************************
134 * NAME EXPORTED
135 * KfLowerIrql
136 *
137 * DESCRIPTION
138 * Restores the irq level on the current processor
139 *
140 * ARGUMENTS
141 * NewIrql = Irql to lower to
142 *
143 * RETURN VALUE
144 * None
145 *
146 * NOTES
147 * Uses fastcall convention
148 */
149 VOID FASTCALL
150 KfLowerIrql (KIRQL NewIrql)
151 {
152 KIRQL OldIrql;
153
154 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
155
156 if (NewIrql > CurrentIrql)
157 {
158 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
159 __FILE__, __LINE__, NewIrql, CurrentIrql);
160 KeBugCheck(0);
161 for(;;);
162 }
163
164 HalpLowerIrql(NewIrql);
165 }
166
167
168 /**********************************************************************
169 * NAME EXPORTED
170 * KeLowerIrql
171 *
172 * DESCRIPTION
173 * Restores the irq level on the current processor
174 *
175 * ARGUMENTS
176 * NewIrql = Irql to lower to
177 *
178 * RETURN VALUE
179 * None
180 *
181 * NOTES
182 */
183
184 VOID STDCALL
185 KeLowerIrql (KIRQL NewIrql)
186 {
187 KfLowerIrql (NewIrql);
188 }
189
190
191 /**********************************************************************
192 * NAME EXPORTED
193 * KfRaiseIrql
194 *
195 * DESCRIPTION
196 * Raises the hardware priority (irql)
197 *
198 * ARGUMENTS
199 * NewIrql = Irql to raise to
200 *
201 * RETURN VALUE
202 * previous irq level
203 *
204 * NOTES
205 * Uses fastcall convention
206 */
207
208 KIRQL FASTCALL
209 KfRaiseIrql (KIRQL NewIrql)
210 {
211 KIRQL OldIrql;
212
213 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
214
215 if (NewIrql < CurrentIrql)
216 {
217 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
218 __FILE__,__LINE__,CurrentIrql,NewIrql);
219 KeBugCheck (0);
220 for(;;);
221 }
222
223 OldIrql = CurrentIrql;
224 CurrentIrql = NewIrql;
225 return OldIrql;
226 }
227
228
229 /**********************************************************************
230 * NAME EXPORTED
231 * KeRaiseIrql
232 *
233 * DESCRIPTION
234 * Raises the hardware priority (irql)
235 *
236 * ARGUMENTS
237 * NewIrql = Irql to raise to
238 * OldIrql (OUT) = Caller supplied storage for the previous irql
239 *
240 * RETURN VALUE
241 * None
242 *
243 * NOTES
244 * Calls KfRaiseIrql
245 */
246 VOID STDCALL
247 KeRaiseIrql (KIRQL NewIrql,
248 PKIRQL OldIrql)
249 {
250 *OldIrql = KfRaiseIrql (NewIrql);
251 }
252
253
254 /**********************************************************************
255 * NAME EXPORTED
256 * KeRaiseIrqlToDpcLevel
257 *
258 * DESCRIPTION
259 * Raises the hardware priority (irql) to DISPATCH level
260 *
261 * ARGUMENTS
262 * None
263 *
264 * RETURN VALUE
265 * Previous irq level
266 *
267 * NOTES
268 * Calls KfRaiseIrql
269 */
270
271 KIRQL STDCALL
272 KeRaiseIrqlToDpcLevel (VOID)
273 {
274 return KfRaiseIrql (DISPATCH_LEVEL);
275 }
276
277
278 /**********************************************************************
279 * NAME EXPORTED
280 * KeRaiseIrqlToSynchLevel
281 *
282 * DESCRIPTION
283 * Raises the hardware priority (irql) to CLOCK2 level
284 *
285 * ARGUMENTS
286 * None
287 *
288 * RETURN VALUE
289 * Previous irq level
290 *
291 * NOTES
292 * Calls KfRaiseIrql
293 */
294
295 KIRQL STDCALL
296 KeRaiseIrqlToSynchLevel (VOID)
297 {
298 return KfRaiseIrql (CLOCK2_LEVEL);
299 }
300
301
302 BOOLEAN STDCALL
303 HalBeginSystemInterrupt (ULONG Vector,
304 KIRQL Irql,
305 PKIRQL OldIrql)
306 {
307 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
308 {
309 return(FALSE);
310 }
311
312 /* Send EOI to the PICs */
313 WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
314 if ((Vector-IRQ_BASE)>=8)
315 {
316 WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
317 }
318
319 if (CurrentIrql >= Irql)
320 {
321 HalpPendingInterruptCount[Vector - IRQ_BASE]++;
322 return(FALSE);
323 }
324 *OldIrql = CurrentIrql;
325 CurrentIrql = Irql;
326
327 return(TRUE);
328 }
329
330
331 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
332 /*
333 * FUNCTION: Finish a system interrupt and restore the specified irq level.
334 */
335 {
336 HalpLowerIrql(Irql);
337 }
338
339 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
340 ULONG Unknown2)
341 {
342 ULONG irq;
343
344 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
345 return FALSE;
346
347 irq = Vector - IRQ_BASE;
348 if (irq < 8)
349 {
350 WRITE_PORT_UCHAR((PUCHAR)0x21,
351 READ_PORT_UCHAR((PUCHAR)0x21)|(1<<irq));
352 }
353 else
354 {
355 WRITE_PORT_UCHAR((PUCHAR)0xa1,
356 READ_PORT_UCHAR((PUCHAR)0xa1)|(1<<(irq-8)));
357 }
358
359 return TRUE;
360 }
361
362
363 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
364 ULONG Unknown2,
365 ULONG Unknown3)
366 {
367 ULONG irq;
368
369 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
370 return FALSE;
371
372 irq = Vector - IRQ_BASE;
373 if (irq < 8)
374 {
375 WRITE_PORT_UCHAR((PUCHAR)0x21,
376 READ_PORT_UCHAR((PUCHAR)0x21)&(~(1<<irq)));
377 }
378 else
379 {
380 WRITE_PORT_UCHAR((PUCHAR)0xa1,
381 READ_PORT_UCHAR((PUCHAR)0xa1)&(~(1<<(irq-8))));
382 }
383
384 return TRUE;
385 }
386
387 /* EOF */