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