update for HEAD-2003050101
[reactos.git] / 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$
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 #ifdef KDBG
45 #include <../dbg/kdb.h>
46 #endif /* KDBG */
47
48 #ifdef MP
49 #include <internal/hal/mps.h>
50 #endif /* MP */
51
52 #define NDEBUG
53 #include <internal/debug.h>
54
55 /* GLOBALS *****************************************************************/
56
57 #ifdef MP
58
59 /* 
60  * FIXME: This does not work if we have more than 24 IRQs (ie. more than one 
61  * I/O APIC) 
62  */
63 #define VECTOR2IRQ(vector) (((vector) - FIRST_DEVICE_VECTOR) / 8)
64 #define IRQ2VECTOR(vector) ((vector * 8) + FIRST_DEVICE_VECTOR)
65 #define VECTOR2IRQL(vector) (DISPATCH_LEVEL /* 2 */ + 1 + VECTOR2IRQ(vector))
66
67
68 #define IRQ_BASE        0x30
69 #define NR_IRQS         0x100 - IRQ_BASE
70
71 #define __STR(x) #x
72 #define STR(x) __STR(x)
73
74 #define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
75 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
76
77 #define BUILD_COMMON_INTERRUPT_HANDLER() \
78 __asm__( \
79   "_KiCommonInterrupt:\n\t" \
80   "cld\n\t" \
81   "pushl %ds\n\t" \
82   "pushl %es\n\t" \
83   "pushl %fs\n\t" \
84   "pushl %gs\n\t" \
85   "movl $0xceafbeef,%eax\n\t" \
86   "pushl %eax\n\t" \
87   "movl $" STR(KERNEL_DS) ",%eax\n\t" \
88   "movl %eax,%ds\n\t" \
89   "movl %eax,%es\n\t" \
90   "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
91   "movl %eax,%fs\n\t" \
92   "pushl %esp\n\t" \
93   "pushl %ebx\n\t" \
94   "call _KiInterruptDispatch\n\t" \
95   "popl %eax\n\t" \
96   "popl %eax\n\t" \
97   "popl %eax\n\t" \
98   "popl %gs\n\t" \
99   "popl %fs\n\t" \
100   "popl %es\n\t" \
101   "popl %ds\n\t" \
102   "popa\n\t" \
103   "iret\n\t");
104
105 #define BUILD_INTERRUPT_HANDLER(intnum) \
106 VOID INT_NAME2(intnum)(VOID); \
107 __asm__( \
108   STR(INT_NAME(intnum)) ":\n\t" \
109   "pusha\n\t" \
110   "movl $0x" STR(intnum) ",%ebx\n\t" \
111   "jmp _KiCommonInterrupt");
112
113
114 /* Interrupt handlers and declarations */
115
116 #define B(x,y) \
117   BUILD_INTERRUPT_HANDLER(x##y)
118
119 #define B16(x) \
120   B(x,0) B(x,1) B(x,2) B(x,3) \
121   B(x,4) B(x,5) B(x,6) B(x,7) \
122   B(x,8) B(x,9) B(x,A) B(x,B) \
123   B(x,C) B(x,D) B(x,E) B(x,F)
124
125
126 BUILD_COMMON_INTERRUPT_HANDLER()
127 B16(3) B16(4) B16(5) B16(6)
128 B16(7) B16(8) B16(9) B16(A)
129 B16(B) B16(C) B16(D) B16(E)
130 B16(F)
131
132 #undef B
133 #undef B16
134
135
136 /* Interrupt handler list */
137
138 #define L(x,y) \
139   (ULONG)& INT_NAME2(x##y)
140
141 #define L16(x) \
142         L(x,0), L(x,1), L(x,2), L(x,3), \
143         L(x,4), L(x,5), L(x,6), L(x,7), \
144         L(x,8), L(x,9), L(x,A), L(x,B), \
145         L(x,C), L(x,D), L(x,E), L(x,F)
146
147 static ULONG irq_handler[NR_IRQS] = {
148   L16(3), L16(4), L16(5), L16(6),
149   L16(7), L16(8), L16(9), L16(A),
150   L16(B), L16(C), L16(D), L16(E),
151   L16(F)
152 };
153
154 #undef L
155 #undef L16
156
157 #else /* MP */
158
159 #define NR_IRQS         (16)
160 #define IRQ_BASE        (0x40)
161
162  void irq_handler_0(void);
163  void irq_handler_1(void);
164  void irq_handler_2(void);
165  void irq_handler_3(void);
166  void irq_handler_4(void);
167  void irq_handler_5(void);
168  void irq_handler_6(void);
169  void irq_handler_7(void);
170  void irq_handler_8(void);
171  void irq_handler_9(void);
172  void irq_handler_10(void);
173  void irq_handler_11(void);
174  void irq_handler_12(void);
175  void irq_handler_13(void);
176  void irq_handler_14(void);
177  void irq_handler_15(void);
178
179 static unsigned int irq_handler[NR_IRQS]=
180         {
181                 (int)&irq_handler_0,
182                 (int)&irq_handler_1,
183                 (int)&irq_handler_2,
184                 (int)&irq_handler_3,
185                 (int)&irq_handler_4,
186                 (int)&irq_handler_5,
187                 (int)&irq_handler_6,
188                 (int)&irq_handler_7,
189                 (int)&irq_handler_8,
190                 (int)&irq_handler_9,
191                 (int)&irq_handler_10,
192                 (int)&irq_handler_11,
193                 (int)&irq_handler_12,
194                 (int)&irq_handler_13,
195                 (int)&irq_handler_14,
196                 (int)&irq_handler_15,
197         };
198
199 #endif /* MP */
200
201 /*
202  * PURPOSE: Object describing each isr 
203  * NOTE: The data in this table is only modified at passsive level but can
204  * be accessed at any irq level.
205  */
206
207 static LIST_ENTRY isr_table[NR_IRQS]={{NULL,NULL},};
208 static PKSPIN_LOCK isr_lock[NR_IRQS] = {NULL,};
209 static KSPIN_LOCK isr_table_lock = {0,};
210
211 #define TAG_ISR_LOCK     TAG('I', 'S', 'R', 'L')
212 #define TAG_KINTERRUPT   TAG('K', 'I', 'S', 'R')
213
214 /* FUNCTIONS ****************************************************************/
215
216 #define PRESENT (0x8000)
217 #define I486_INTERRUPT_GATE (0xe00)
218
219 VOID KeInitInterrupts (VOID)
220 {
221    int i;
222
223 #ifdef MP
224
225    /*
226     * Setup the IDT entries to point to the interrupt handlers
227     */
228    for (i=0;i<NR_IRQS;i++)
229      {
230         KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
231         KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
232                             I486_INTERRUPT_GATE;
233         InitializeListHead(&isr_table[i]);
234      }
235
236 #else
237
238    /*
239     * Setup the IDT entries to point to the interrupt handlers
240     */
241    for (i=0;i<NR_IRQS;i++)
242      {
243         KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
244         KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
245                             I486_INTERRUPT_GATE;
246         InitializeListHead(&isr_table[i]);
247      }
248
249 #endif
250
251 }
252
253 typedef struct _KIRQ_TRAPFRAME
254 {
255    ULONG Magic;
256    ULONG Fs;
257    ULONG Es;
258    ULONG Ds;
259    ULONG Eax;
260    ULONG Ecx;
261    ULONG Edx;
262    ULONG Ebx;
263    ULONG Esp;
264    ULONG Ebp;
265    ULONG Esi;
266    ULONG Edi;
267    ULONG Eip;
268    ULONG Cs;
269    ULONG Eflags;
270 } KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
271
272 #ifdef DBG
273
274 VOID
275 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
276   PKTRAP_FRAME TrapFrame)
277 {
278    TrapFrame->Fs     = IrqTrapFrame->Fs;
279    TrapFrame->Fs     = IrqTrapFrame->Es;
280    TrapFrame->Ds     = 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 #endif
295
296 #ifdef MP
297
298 VOID STDCALL
299 KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
300 /*
301  * FUNCTION: Calls all the interrupt handlers for a given irq.
302  * ARGUMENTS:
303  *        vector - The number of the vector to call handlers for.
304  *        old_level - The irql of the processor when the irq took place.
305  * NOTES: Must be called at DIRQL.
306  */
307 {
308   PKINTERRUPT isr;
309   PLIST_ENTRY current;
310
311   DPRINT1("I(0x%.08x, 0x%.08x)\n", vector, old_level);
312
313   if (vector == 0)
314     {
315           KiUpdateSystemTime(old_level, 0);
316     }
317   else
318     {
319       /*
320        * Iterate the list until one of the isr tells us its device interrupted
321        */
322       current = isr_table[vector].Flink;
323       isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
324
325       while (current != &isr_table[vector] && 
326              !isr->ServiceRoutine(isr, isr->ServiceContext))
327         {
328           current = current->Flink;
329           isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
330         }
331    }
332 }
333
334 VOID
335 KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
336 /*
337  * FUNCTION: Calls the irq specific handler for an irq
338  * ARGUMENTS:
339  *         Vector    = Interrupt vector
340  *         Trapframe = CPU context
341  * NOTES: Interrupts are disabled at this point.
342  */
343 {
344    KIRQL old_level;
345
346 #ifdef DBG
347
348    KTRAP_FRAME KernelTrapFrame;
349
350    KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
351    KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
352
353 #endif /* DBG */
354
355    DbgPrint("V(0x%.02x)", Vector);
356
357    /*
358     * Notify the rest of the kernel of the raised irq level
359     */
360    if (!HalBeginSystemInterrupt (Vector,
361                             VECTOR2IRQL(Vector),
362                             &old_level))
363      {
364        return;
365      }
366
367    /*
368     * Mask the related irq
369     */
370    //HalDisableSystemInterrupt (Vector, 0);
371
372    /*
373     * Enable interrupts
374     * NOTE: Only higher priority interrupts will get through
375     */
376    __asm__("sti\n\t");
377
378    /*
379     * Actually call the ISR.
380     */
381    KiInterruptDispatch2(Vector, old_level);
382
383    /*
384     * Disable interrupts
385     */
386    __asm__("cli\n\t");
387
388    /*
389     * Unmask the related irq
390     */
391    //HalEnableSystemInterrupt (Vector, 0, 0);
392
393    //DbgPrint("E(0x%.02x)\n", Vector);
394
395    /*
396     * End the system interrupt.
397     */
398   HalEndSystemInterrupt (old_level, 0);
399 }
400
401 #else /* MP */
402
403 VOID STDCALL
404 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
405 /*
406  * FUNCTION: Calls all the interrupt handlers for a given irq.
407  * ARGUMENTS:
408  *        Irq - The number of the irq to call handlers for.
409  *        old_level - The irql of the processor when the irq took place.
410  * NOTES: Must be called at DIRQL.
411  */
412 {
413   PKINTERRUPT isr;
414   PLIST_ENTRY current;
415
416   if (Irq == 0)
417     {
418       KiUpdateSystemTime(old_level, 0);
419     }
420   else
421     {
422       /*
423        * Iterate the list until one of the isr tells us its device interrupted
424        */
425       current = isr_table[Irq].Flink;
426       while (current != &isr_table[Irq])
427       { 
428           isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
429 #if 0
430           if (isr->ServiceRoutine(isr, isr->ServiceContext))
431           {
432              break;
433           }
434 #else
435           isr->ServiceRoutine(isr, isr->ServiceContext);
436 #endif
437           current = current->Flink;
438       }
439    }
440 }
441
442 VOID 
443 KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
444 /*
445  * FUNCTION: Calls the irq specific handler for an irq
446  * ARGUMENTS:
447  *         irq = IRQ that has interrupted
448  */
449 {
450    KIRQL old_level;
451
452    /*
453     * At this point we have interrupts disabled, nothing has been done to
454     * the PIC.
455     */
456
457    /*
458     * Notify the rest of the kernel of the raised irq level. For the
459     * default HAL this will send an EOI to the PIC and alter the IRQL.
460     */
461    if (!HalBeginSystemInterrupt (irq + IRQ_BASE,
462                                  PROFILE_LEVEL - irq,
463                                  &old_level))
464      {
465        return;
466      }
467
468    /*
469     * Enable interrupts
470     * NOTE: Only higher priority interrupts will get through
471     */
472    __asm__("sti\n\t");
473
474    /*
475     * Actually call the ISR.
476     */
477    KiInterruptDispatch2(irq, old_level);
478
479 #ifdef KDBG
480    if (irq == 0)
481      {
482        KdbProfileInterrupt(Trapframe->Eip);
483      }
484 #endif /* KDBG */
485
486    /*
487     * Maybe do a reschedule as well.
488     */
489    if (old_level < DISPATCH_LEVEL && irq == 0)
490      {
491        KeLowerIrql(APC_LEVEL);
492        PsDispatchThread(THREAD_STATE_READY);
493      }
494
495    /*
496     * End the system interrupt.
497     */
498    __asm__("cli\n\t");
499    HalEndSystemInterrupt (old_level, 0);
500 }
501
502 #endif /* MP */
503
504 static VOID 
505 KeDumpIrqList(VOID)
506 {
507    PKINTERRUPT current;
508    PLIST_ENTRY current_entry;
509    unsigned int i;
510    
511    for (i=0;i<NR_IRQS;i++)
512      {
513         DPRINT("For irq %x ",i);
514         current_entry = isr_table[i].Flink;
515         current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
516         while (current_entry!=(&isr_table[i]))
517           {
518              DPRINT("Isr %x ",current);
519              current_entry = current_entry->Flink;
520              current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
521           }
522         DPRINT("\n",0);
523      }
524 }
525
526 NTSTATUS STDCALL
527 KeConnectInterrupt(PKINTERRUPT InterruptObject)
528 {
529    KIRQL oldlvl;
530    KIRQL synch_oldlvl;
531    PKINTERRUPT ListHead;
532    ULONG Vector;
533
534    DPRINT("KeConnectInterrupt()\n");
535
536    Vector = InterruptObject->Vector;
537
538    /*
539     * Acquire the table spinlock
540     */
541    KeAcquireSpinLock(&isr_table_lock,&oldlvl);
542    
543    /*
544     * Check if the vector is already in use that we can share it
545     */
546    ListHead = CONTAINING_RECORD(isr_table[Vector].Flink,KINTERRUPT,Entry);
547    if (!IsListEmpty(&isr_table[Vector]) &&
548        (InterruptObject->Shareable == FALSE || ListHead->Shareable==FALSE))
549      {
550         KeReleaseSpinLock(&isr_table_lock,oldlvl);
551         return(STATUS_INVALID_PARAMETER);
552      }
553    else
554      {
555         isr_lock[Vector] =
556           ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK),
557                                 TAG_ISR_LOCK);
558         KeInitializeSpinLock(isr_lock[Vector]);
559      }
560
561    InterruptObject->IrqLock = isr_lock[Vector];
562
563    KeRaiseIrql(InterruptObject->SynchLevel,&synch_oldlvl);
564    KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
565    DPRINT("%x %x\n",isr_table[Vector].Flink,isr_table[Vector].Blink);
566    if (IsListEmpty(&isr_table[Vector]))
567    {
568 #ifdef MP
569     HalEnableSystemInterrupt(Vector, 0, 0);
570 #else
571         HalEnableSystemInterrupt(Vector + IRQ_BASE, 0, 0);
572 #endif
573    }
574    InsertTailList(&isr_table[Vector],&InterruptObject->Entry);
575    DPRINT("%x %x\n",InterruptObject->Entry.Flink,
576           InterruptObject->Entry.Blink);
577    KeReleaseSpinLockFromDpcLevel(InterruptObject->IrqLock);
578    KeLowerIrql(synch_oldlvl);
579    
580    /*
581     * Release the table spinlock
582     */
583    KeReleaseSpinLock(&isr_table_lock,oldlvl);
584    
585    KeDumpIrqList();
586
587    return STATUS_SUCCESS;
588 }
589
590
591 VOID STDCALL
592 KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
593 /*
594  * FUNCTION: Releases a drivers isr
595  * ARGUMENTS:
596  *        InterruptObject = isr to release
597  */
598 {
599    KIRQL oldlvl;
600    
601    KeRaiseIrql(InterruptObject->SynchLevel,&oldlvl);
602    KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
603    RemoveEntryList(&InterruptObject->Entry);
604    if (IsListEmpty(&isr_table[InterruptObject->Vector]))
605    {
606 #ifdef MP
607           HalDisableSystemInterrupt(InterruptObject->Vector, 0);
608 #else
609       HalDisableSystemInterrupt(InterruptObject->Vector + IRQ_BASE, 0);
610 #endif
611    }
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 */