- Replaced some common sequences of inline assembly with macros. Avoid
[reactos.git] / reactos / ntoskrnl / ke / i386 / irq.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: irq.c,v 1.41 2004/03/09 21:49:53 dwelch Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/i386/irq.c
23 * PURPOSE: IRQ handling
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * 29/05/98: Created
27 */
28
29 /*
30 * NOTE: In general the PIC interrupt priority facilities are used to
31 * preserve the NT IRQL semantics, global interrupt disables are only used
32 * to keep the PIC in a consistent state
33 *
34 */
35
36 /* INCLUDES ****************************************************************/
37
38 #define NTOS_MODE_KERNEL
39 #include <ntos.h>
40 #include <roscfg.h>
41 #include <internal/ke.h>
42 #include <internal/ps.h>
43 #include <internal/i386/segment.h>
44 #include <internal/pool.h>
45 #ifdef KDBG
46 #include <../dbg/kdb.h>
47 #endif /* KDBG */
48
49 #ifdef MP
50 #include <internal/hal/mps.h>
51 #endif /* MP */
52
53 #define NDEBUG
54 #include <internal/debug.h>
55
56 /* GLOBALS *****************************************************************/
57
58 #ifdef MP
59
60 /*
61 * FIXME: This does not work if we have more than 24 IRQs (ie. more than one
62 * I/O APIC)
63 */
64 #define VECTOR2IRQ(vector) (((vector) - FIRST_DEVICE_VECTOR) / 8)
65 #define IRQ2VECTOR(vector) ((vector * 8) + FIRST_DEVICE_VECTOR)
66 #define VECTOR2IRQL(vector) (DISPATCH_LEVEL /* 2 */ + 1 + VECTOR2IRQ(vector))
67
68
69 #define IRQ_BASE 0x30
70 #define NR_IRQS 0x100 - IRQ_BASE
71
72 #define __STR(x) #x
73 #define STR(x) __STR(x)
74
75 #define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
76 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
77
78 #define BUILD_COMMON_INTERRUPT_HANDLER() \
79 __asm__( \
80 "_KiCommonInterrupt:\n\t" \
81 "cld\n\t" \
82 "pushl %ds\n\t" \
83 "pushl %es\n\t" \
84 "pushl %fs\n\t" \
85 "pushl %gs\n\t" \
86 "movl $0xceafbeef,%eax\n\t" \
87 "pushl %eax\n\t" \
88 "movl $" STR(KERNEL_DS) ",%eax\n\t" \
89 "movl %eax,%ds\n\t" \
90 "movl %eax,%es\n\t" \
91 "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
92 "movl %eax,%fs\n\t" \
93 "pushl %esp\n\t" \
94 "pushl %ebx\n\t" \
95 "call _KiInterruptDispatch\n\t" \
96 "popl %eax\n\t" \
97 "popl %eax\n\t" \
98 "popl %eax\n\t" \
99 "popl %gs\n\t" \
100 "popl %fs\n\t" \
101 "popl %es\n\t" \
102 "popl %ds\n\t" \
103 "popa\n\t" \
104 "iret\n\t");
105
106 #define BUILD_INTERRUPT_HANDLER(intnum) \
107 VOID INT_NAME2(intnum)(VOID); \
108 __asm__( \
109 STR(INT_NAME(intnum)) ":\n\t" \
110 "pusha\n\t" \
111 "movl $0x" STR(intnum) ",%ebx\n\t" \
112 "jmp _KiCommonInterrupt");
113
114
115 /* Interrupt handlers and declarations */
116
117 #define B(x,y) \
118 BUILD_INTERRUPT_HANDLER(x##y)
119
120 #define B16(x) \
121 B(x,0) B(x,1) B(x,2) B(x,3) \
122 B(x,4) B(x,5) B(x,6) B(x,7) \
123 B(x,8) B(x,9) B(x,A) B(x,B) \
124 B(x,C) B(x,D) B(x,E) B(x,F)
125
126
127 BUILD_COMMON_INTERRUPT_HANDLER()
128 B16(3) B16(4) B16(5) B16(6)
129 B16(7) B16(8) B16(9) B16(A)
130 B16(B) B16(C) B16(D) B16(E)
131 B16(F)
132
133 #undef B
134 #undef B16
135
136
137 /* Interrupt handler list */
138
139 #define L(x,y) \
140 (ULONG)& INT_NAME2(x##y)
141
142 #define L16(x) \
143 L(x,0), L(x,1), L(x,2), L(x,3), \
144 L(x,4), L(x,5), L(x,6), L(x,7), \
145 L(x,8), L(x,9), L(x,A), L(x,B), \
146 L(x,C), L(x,D), L(x,E), L(x,F)
147
148 static ULONG irq_handler[NR_IRQS] = {
149 L16(3), L16(4), L16(5), L16(6),
150 L16(7), L16(8), L16(9), L16(A),
151 L16(B), L16(C), L16(D), L16(E),
152 L16(F)
153 };
154
155 #undef L
156 #undef L16
157
158 #else /* MP */
159
160 #define NR_IRQS (16)
161 #define IRQ_BASE (0x40)
162
163 void irq_handler_0(void);
164 void irq_handler_1(void);
165 void irq_handler_2(void);
166 void irq_handler_3(void);
167 void irq_handler_4(void);
168 void irq_handler_5(void);
169 void irq_handler_6(void);
170 void irq_handler_7(void);
171 void irq_handler_8(void);
172 void irq_handler_9(void);
173 void irq_handler_10(void);
174 void irq_handler_11(void);
175 void irq_handler_12(void);
176 void irq_handler_13(void);
177 void irq_handler_14(void);
178 void irq_handler_15(void);
179
180 static unsigned int irq_handler[NR_IRQS]=
181 {
182 (int)&irq_handler_0,
183 (int)&irq_handler_1,
184 (int)&irq_handler_2,
185 (int)&irq_handler_3,
186 (int)&irq_handler_4,
187 (int)&irq_handler_5,
188 (int)&irq_handler_6,
189 (int)&irq_handler_7,
190 (int)&irq_handler_8,
191 (int)&irq_handler_9,
192 (int)&irq_handler_10,
193 (int)&irq_handler_11,
194 (int)&irq_handler_12,
195 (int)&irq_handler_13,
196 (int)&irq_handler_14,
197 (int)&irq_handler_15,
198 };
199
200 #endif /* MP */
201
202 /*
203 * PURPOSE: Object describing each isr
204 * NOTE: The data in this table is only modified at passsive level but can
205 * be accessed at any irq level.
206 */
207
208 static LIST_ENTRY isr_table[NR_IRQS]={{NULL,NULL},};
209 static PKSPIN_LOCK isr_lock[NR_IRQS] = {NULL,};
210 static KSPIN_LOCK isr_table_lock = {0,};
211
212 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
213 #define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R')
214
215 /* FUNCTIONS ****************************************************************/
216
217 #define PRESENT (0x8000)
218 #define I486_INTERRUPT_GATE (0xe00)
219
220 VOID INIT_FUNCTION
221 KeInitInterrupts (VOID)
222 {
223 int i;
224
225 #ifdef MP
226
227 /*
228 * Setup the IDT entries to point to the interrupt handlers
229 */
230 for (i=0;i<NR_IRQS;i++)
231 {
232 KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
233 KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
234 I486_INTERRUPT_GATE;
235 InitializeListHead(&isr_table[i]);
236 }
237
238 #else
239
240 /*
241 * Setup the IDT entries to point to the interrupt handlers
242 */
243 for (i=0;i<NR_IRQS;i++)
244 {
245 KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
246 KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
247 I486_INTERRUPT_GATE;
248 InitializeListHead(&isr_table[i]);
249 }
250
251 #endif
252
253 }
254
255 typedef struct _KIRQ_TRAPFRAME
256 {
257 ULONG Magic;
258 ULONG Fs;
259 ULONG Es;
260 ULONG Ds;
261 ULONG Eax;
262 ULONG Ecx;
263 ULONG Edx;
264 ULONG Ebx;
265 ULONG Esp;
266 ULONG Ebp;
267 ULONG Esi;
268 ULONG Edi;
269 ULONG Eip;
270 ULONG Cs;
271 ULONG Eflags;
272 } KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
273
274 VOID
275 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
276 PKTRAP_FRAME TrapFrame)
277 {
278 TrapFrame->Fs = (USHORT)IrqTrapFrame->Fs;
279 TrapFrame->Es = (USHORT)IrqTrapFrame->Es;
280 TrapFrame->Ds = (USHORT)IrqTrapFrame->Ds;
281 TrapFrame->Eax = IrqTrapFrame->Eax;
282 TrapFrame->Ecx = IrqTrapFrame->Ecx;
283 TrapFrame->Edx = IrqTrapFrame->Edx;
284 TrapFrame->Ebx = IrqTrapFrame->Ebx;
285 TrapFrame->Esp = IrqTrapFrame->Esp;
286 TrapFrame->Ebp = IrqTrapFrame->Ebp;
287 TrapFrame->Esi = IrqTrapFrame->Esi;
288 TrapFrame->Edi = IrqTrapFrame->Edi;
289 TrapFrame->Eip = IrqTrapFrame->Eip;
290 TrapFrame->Cs = IrqTrapFrame->Cs;
291 TrapFrame->Eflags = IrqTrapFrame->Eflags;
292 }
293
294 VOID
295 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
296 PKIRQ_TRAPFRAME IrqTrapFrame)
297 {
298 IrqTrapFrame->Fs = TrapFrame->Fs;
299 IrqTrapFrame->Es = TrapFrame->Es;
300 IrqTrapFrame->Ds = TrapFrame->Ds;
301 IrqTrapFrame->Eax = TrapFrame->Eax;
302 IrqTrapFrame->Ecx = TrapFrame->Ecx;
303 IrqTrapFrame->Edx = TrapFrame->Edx;
304 IrqTrapFrame->Ebx = TrapFrame->Ebx;
305 IrqTrapFrame->Esp = TrapFrame->Esp;
306 IrqTrapFrame->Ebp = TrapFrame->Ebp;
307 IrqTrapFrame->Esi = TrapFrame->Esi;
308 IrqTrapFrame->Edi = TrapFrame->Edi;
309 IrqTrapFrame->Eip = TrapFrame->Eip;
310 IrqTrapFrame->Cs = TrapFrame->Cs;
311 IrqTrapFrame->Eflags = TrapFrame->Eflags;
312 }
313
314 #ifdef MP
315
316 VOID STDCALL
317 KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
318 /*
319 * FUNCTION: Calls all the interrupt handlers for a given irq.
320 * ARGUMENTS:
321 * vector - The number of the vector to call handlers for.
322 * old_level - The irql of the processor when the irq took place.
323 * NOTES: Must be called at DIRQL.
324 */
325 {
326 PKINTERRUPT isr;
327 PLIST_ENTRY current;
328
329 DPRINT1("I(0x%.08x, 0x%.08x)\n", vector, old_level);
330
331 if (vector == 0)
332 {
333 KiUpdateSystemTime(old_level, 0);
334 }
335 else
336 {
337 /*
338 * Iterate the list until one of the isr tells us its device interrupted
339 */
340 current = isr_table[vector].Flink;
341 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
342
343 while (current != &isr_table[vector] &&
344 !isr->ServiceRoutine(isr, isr->ServiceContext))
345 {
346 current = current->Flink;
347 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
348 }
349 }
350 }
351
352 VOID
353 KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
354 /*
355 * FUNCTION: Calls the irq specific handler for an irq
356 * ARGUMENTS:
357 * Vector = Interrupt vector
358 * Trapframe = CPU context
359 * NOTES: Interrupts are disabled at this point.
360 */
361 {
362 KIRQL old_level;
363
364 #ifdef DBG
365
366 KTRAP_FRAME KernelTrapFrame;
367
368 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
369 KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
370
371 #endif /* DBG */
372
373 DbgPrint("V(0x%.02x)", Vector);
374
375 /*
376 * Notify the rest of the kernel of the raised irq level
377 */
378 if (!HalBeginSystemInterrupt (Vector,
379 VECTOR2IRQL(Vector),
380 &old_level))
381 {
382 return;
383 }
384
385 /*
386 * Mask the related irq
387 */
388 //HalDisableSystemInterrupt (Vector, 0);
389
390 /*
391 * Enable interrupts
392 * NOTE: Only higher priority interrupts will get through
393 */
394 Ke386EnableInterrupts();
395
396 /*
397 * Actually call the ISR.
398 */
399 KiInterruptDispatch2(Vector, old_level);
400
401 /*
402 * Disable interrupts
403 */
404 Ke386DisableInterrupts();
405
406 /*
407 * Unmask the related irq
408 */
409 //HalEnableSystemInterrupt (Vector, 0, 0);
410
411 //DbgPrint("E(0x%.02x)\n", Vector);
412
413 /*
414 * End the system interrupt.
415 */
416 HalEndSystemInterrupt (old_level, 0);
417 }
418
419 #else /* MP */
420
421 VOID STDCALL
422 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
423 /*
424 * FUNCTION: Calls all the interrupt handlers for a given irq.
425 * ARGUMENTS:
426 * Irq - The number of the irq to call handlers for.
427 * old_level - The irql of the processor when the irq took place.
428 * NOTES: Must be called at DIRQL.
429 */
430 {
431 PKINTERRUPT isr;
432 PLIST_ENTRY current;
433
434 if (Irq == 0)
435 {
436 KiUpdateSystemTime(old_level, 0);
437 }
438 else
439 {
440 /*
441 * Iterate the list until one of the isr tells us its device interrupted
442 */
443 current = isr_table[Irq].Flink;
444 while (current != &isr_table[Irq])
445 {
446 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
447 #if 0
448 if (isr->ServiceRoutine(isr, isr->ServiceContext))
449 {
450 break;
451 }
452 #else
453 isr->ServiceRoutine(isr, isr->ServiceContext);
454 #endif
455 current = current->Flink;
456 }
457 }
458 }
459
460 VOID
461 KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
462 /*
463 * FUNCTION: Calls the irq specific handler for an irq
464 * ARGUMENTS:
465 * irq = IRQ that has interrupted
466 */
467 {
468 KIRQL old_level;
469 KTRAP_FRAME KernelTrapFrame;
470 PKTHREAD CurrentThread;
471 PKTRAP_FRAME OldTrapFrame=NULL;
472
473 /*
474 * At this point we have interrupts disabled, nothing has been done to
475 * the PIC.
476 */
477
478 /*
479 * Notify the rest of the kernel of the raised irq level. For the
480 * default HAL this will send an EOI to the PIC and alter the IRQL.
481 */
482 if (!HalBeginSystemInterrupt (irq + IRQ_BASE,
483 (KIRQL)(PROFILE_LEVEL - irq),
484 &old_level))
485 {
486 return;
487 }
488
489
490 /*
491 * Enable interrupts
492 * NOTE: Only higher priority interrupts will get through
493 */
494 Ke386EnableInterrupts();
495
496 /*
497 * Actually call the ISR.
498 */
499 KiInterruptDispatch2(irq, old_level);
500
501 #ifdef KDBG
502 if (irq == 0)
503 {
504 KdbProfileInterrupt(Trapframe->Eip);
505 }
506 #endif /* KDBG */
507
508 /*
509 * Maybe do a reschedule as well.
510 */
511 if (old_level < DISPATCH_LEVEL && irq == 0)
512 {
513 KeLowerIrql(APC_LEVEL);
514 PsDispatchThread(THREAD_STATE_READY);
515 }
516
517 /*
518 * End the system interrupt.
519 */
520 Ke386DisableInterrupts();
521
522 HalEndSystemInterrupt (old_level, 0);
523
524 if (old_level==PASSIVE_LEVEL && Trapframe->Cs != KERNEL_CS)
525 {
526 CurrentThread = KeGetCurrentThread();
527 if (CurrentThread!=NULL && CurrentThread->Alerted[1])
528 {
529 DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
530 ((PETHREAD)CurrentThread)->ThreadsProcess->UniqueProcessId,
531 ((PETHREAD)CurrentThread)->Cid.UniqueThread,
532 Trapframe->Cs,
533 CurrentThread->TrapFrame ? CurrentThread->TrapFrame->Cs : 0);
534 if (CurrentThread->TrapFrame == NULL)
535 {
536 OldTrapFrame = CurrentThread->TrapFrame;
537 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
538 CurrentThread->TrapFrame = &KernelTrapFrame;
539 }
540
541 KiDeliverNormalApc();
542
543 assert(KeGetCurrentThread() == CurrentThread);
544 if (CurrentThread->TrapFrame == &KernelTrapFrame)
545 {
546 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
547 CurrentThread->TrapFrame = OldTrapFrame;
548 }
549 }
550 }
551 }
552
553 #endif /* MP */
554
555 static VOID
556 KeDumpIrqList(VOID)
557 {
558 PKINTERRUPT current;
559 PLIST_ENTRY current_entry;
560 unsigned int i;
561
562 for (i=0;i<NR_IRQS;i++)
563 {
564 DPRINT("For irq %x ",i);
565 current_entry = isr_table[i].Flink;
566 current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
567 while (current_entry!=(&isr_table[i]))
568 {
569 DPRINT("Isr %x ",current);
570 current_entry = current_entry->Flink;
571 current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
572 }
573 DPRINT("\n",0);
574 }
575 }
576
577 /*
578 * @implemented
579 */
580 NTSTATUS STDCALL
581 KeConnectInterrupt(PKINTERRUPT InterruptObject)
582 {
583 KIRQL oldlvl;
584 KIRQL synch_oldlvl;
585 PKINTERRUPT ListHead;
586 ULONG Vector;
587
588 DPRINT("KeConnectInterrupt()\n");
589
590 Vector = InterruptObject->Vector;
591
592 /*
593 * Acquire the table spinlock
594 */
595 KeAcquireSpinLock(&isr_table_lock,&oldlvl);
596
597 /*
598 * Check if the vector is already in use that we can share it
599 */
600 ListHead = CONTAINING_RECORD(isr_table[Vector].Flink,KINTERRUPT,Entry);
601 if (!IsListEmpty(&isr_table[Vector]) &&
602 (InterruptObject->Shareable == FALSE || ListHead->Shareable==FALSE))
603 {
604 KeReleaseSpinLock(&isr_table_lock,oldlvl);
605 return(STATUS_INVALID_PARAMETER);
606 }
607 else
608 {
609 isr_lock[Vector] =
610 ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK),
611 TAG_ISR_LOCK);
612 KeInitializeSpinLock(isr_lock[Vector]);
613 }
614
615 InterruptObject->IrqLock = isr_lock[Vector];
616
617 KeRaiseIrql(InterruptObject->SynchLevel,&synch_oldlvl);
618 KiAcquireSpinLock(InterruptObject->IrqLock);
619 DPRINT("%x %x\n",isr_table[Vector].Flink,isr_table[Vector].Blink);
620 if (IsListEmpty(&isr_table[Vector]))
621 {
622 #ifdef MP
623 HalEnableSystemInterrupt(Vector, 0, 0);
624 #else
625 HalEnableSystemInterrupt(Vector + IRQ_BASE, 0, 0);
626 #endif
627 }
628 InsertTailList(&isr_table[Vector],&InterruptObject->Entry);
629 DPRINT("%x %x\n",InterruptObject->Entry.Flink,
630 InterruptObject->Entry.Blink);
631 KiReleaseSpinLock(InterruptObject->IrqLock);
632 KeLowerIrql(synch_oldlvl);
633
634 /*
635 * Release the table spinlock
636 */
637 KeReleaseSpinLock(&isr_table_lock,oldlvl);
638
639 KeDumpIrqList();
640
641 return STATUS_SUCCESS;
642 }
643
644
645 /*
646 * @implemented
647 */
648 VOID STDCALL
649 KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
650 /*
651 * FUNCTION: Releases a drivers isr
652 * ARGUMENTS:
653 * InterruptObject = isr to release
654 */
655 {
656 KIRQL oldlvl;
657
658 KeRaiseIrql(InterruptObject->SynchLevel,&oldlvl);
659 KiAcquireSpinLock(InterruptObject->IrqLock);
660 RemoveEntryList(&InterruptObject->Entry);
661 if (IsListEmpty(&isr_table[InterruptObject->Vector]))
662 {
663 #ifdef MP
664 HalDisableSystemInterrupt(InterruptObject->Vector, 0);
665 #else
666 HalDisableSystemInterrupt(InterruptObject->Vector + IRQ_BASE, 0);
667 #endif
668 }
669 KiReleaseSpinLock(InterruptObject->IrqLock);
670 KeLowerIrql(oldlvl);
671 }
672
673
674 /*
675 * @implemented
676 */
677 NTSTATUS
678 STDCALL
679 KeInitializeInterrupt(PKINTERRUPT InterruptObject,
680 PKSERVICE_ROUTINE ServiceRoutine,
681 PVOID ServiceContext,
682 PKSPIN_LOCK SpinLock,
683 ULONG Vector,
684 KIRQL Irql,
685 KIRQL SynchronizeIrql,
686 KINTERRUPT_MODE InterruptMode,
687 BOOLEAN ShareVector,
688 KAFFINITY ProcessorEnableMask,
689 BOOLEAN FloatingSave)
690 {
691 InterruptObject->ServiceContext = ServiceContext;
692 InterruptObject->ServiceRoutine = ServiceRoutine;
693 InterruptObject->Vector = Vector;
694 InterruptObject->ProcessorEnableMask = ProcessorEnableMask;
695 InterruptObject->SynchLevel = SynchronizeIrql;
696 InterruptObject->Shareable = ShareVector;
697 InterruptObject->FloatingSave = FALSE;
698
699 return STATUS_SUCCESS;
700 }
701
702
703 /*
704 * @implemented
705 */
706 NTSTATUS STDCALL
707 IoConnectInterrupt(PKINTERRUPT* InterruptObject,
708 PKSERVICE_ROUTINE ServiceRoutine,
709 PVOID ServiceContext,
710 PKSPIN_LOCK SpinLock,
711 ULONG Vector,
712 KIRQL Irql,
713 KIRQL SynchronizeIrql,
714 KINTERRUPT_MODE InterruptMode,
715 BOOLEAN ShareVector,
716 KAFFINITY ProcessorEnableMask,
717 BOOLEAN FloatingSave)
718 /*
719 * FUNCTION: Registers a driver's isr to be called when its device interrupts
720 * ARGUMENTS:
721 * InterruptObject (OUT) = Points to the interrupt object created on
722 * return
723 * ServiceRoutine = Routine to be called when the device interrupts
724 * ServiceContext = Parameter to be passed to ServiceRoutine
725 * SpinLock = Initalized spinlock that will be used to synchronize
726 * access between the isr and other driver routines. This is
727 * required if the isr handles more than one vector or the
728 * driver has more than one isr
729 * Vector = Interrupt vector to allocate
730 * (returned from HalGetInterruptVector)
731 * Irql = DIRQL returned from HalGetInterruptVector
732 * SynchronizeIrql = DIRQL at which the isr will execute. This must
733 * be the highest of all the DIRQLs returned from
734 * HalGetInterruptVector if the driver has multiple
735 * isrs
736 * InterruptMode = Specifies if the interrupt is LevelSensitive or
737 * Latched
738 * ShareVector = Specifies if the vector can be shared
739 * ProcessorEnableMask = Processors on the isr can run
740 * FloatingSave = TRUE if the floating point stack should be saved when
741 * the isr runs. Must be false for x86 drivers
742 * RETURNS: Status
743 * IRQL: PASSIVE_LEVEL
744 */
745 {
746 PKINTERRUPT Interrupt;
747 NTSTATUS Status = STATUS_SUCCESS;
748
749 ASSERT_IRQL(PASSIVE_LEVEL);
750
751 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector);
752
753 /*
754 * Check the parameters
755 */
756 if (Vector >= NR_IRQS)
757 {
758 return(STATUS_INVALID_PARAMETER);
759 }
760 if (FloatingSave == TRUE)
761 {
762 return(STATUS_INVALID_PARAMETER);
763 }
764
765 /*
766 * Initialize interrupt object
767 */
768 Interrupt=ExAllocatePoolWithTag(NonPagedPool,sizeof(KINTERRUPT),
769 TAG_KINTERRUPT);
770 if (Interrupt==NULL)
771 {
772 return(STATUS_INSUFFICIENT_RESOURCES);
773 }
774
775 Status = KeInitializeInterrupt(Interrupt,
776 ServiceRoutine,
777 ServiceContext,
778 SpinLock,
779 Vector,
780 Irql,
781 SynchronizeIrql,
782 InterruptMode,
783 ShareVector,
784 ProcessorEnableMask,
785 FloatingSave);
786 if (!NT_SUCCESS(Status))
787 {
788 ExFreePool(Interrupt);
789 return Status;
790 }
791
792 Status = KeConnectInterrupt(Interrupt);
793 if (!NT_SUCCESS(Status))
794 {
795 ExFreePool(Interrupt);
796 return Status;
797 }
798
799 *InterruptObject = Interrupt;
800
801 return(STATUS_SUCCESS);
802 }
803
804
805 /*
806 * @implemented
807 */
808 VOID STDCALL
809 IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
810 /*
811 * FUNCTION: Releases a drivers isr
812 * ARGUMENTS:
813 * InterruptObject = isr to release
814 */
815 {
816 KeDisconnectInterrupt(InterruptObject);
817 ExFreePool(InterruptObject);
818 }
819
820 /* EOF */