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