- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / ke / i386 / irq.c
index 2d39598..0a567f8 100644 (file)
@@ -1,12 +1,11 @@
-/* $Id: irq.c,v 1.19 2002/05/02 23:45:33 dwelch Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/i386/irq.c
  * PURPOSE:         IRQ handling
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *             29/05/98: Created
+ *
+ * PROGRAMMERS:     David Welch (welch@mcmail.com)
  */
 
 /*
 
 /* INCLUDES ****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <roscfg.h>
-#include <internal/ke.h>
-#include <internal/ps.h>
-#include <internal/i386/segment.h>
-#include <internal/pool.h>
-
-#ifdef MP
-#include <internal/hal/mps.h>
-#endif /* MP */
+#include <ntoskrnl.h>
+#include <../hal/halx86/include/halirq.h>
+#include <../hal/halx86/include/mps.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS *****************************************************************/
 
-#ifdef MP
-
-#define IRQ_BASE  FIRST_DEVICE_VECTOR
-#define NR_IRQS   0x100 - 0x30
+/* Interrupt handler list */
 
-#define __STR(x) #x
-#define STR(x) __STR(x)
+#ifdef CONFIG_SMP
 
-#define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
 
-#define BUILD_COMMON_INTERRUPT_HANDLER() \
-__asm__( \
-  "_KiCommonInterrupt:\n\t" \
-  "cld\n\t" \
-  "pushl %ds\n\t" \
-  "pushl %es\n\t" \
-  "pushl %fs\n\t" \
-  "pushl %gs\n\t" \
-  "movl        $0xceafbeef,%eax\n\t" \
-  "pushl %eax\n\t" \
-  "movl        $" STR(KERNEL_DS) ",%eax\n\t" \
-  "movl        %eax,%ds\n\t" \
-  "movl        %eax,%es\n\t" \
-  "movl        $" STR(PCR_SELECTOR) ",%eax\n\t" \
-  "movl        %eax,%fs\n\t" \
-  "pushl %esp\n\t" \
-  "pushl %ebx\n\t" \
-  "call        _KiInterruptDispatch\n\t" \
-  "popl        %eax\n\t" \
-  "popl        %eax\n\t" \
-  "popl        %eax\n\t" \
-  "popl        %gs\n\t" \
-  "popl        %fs\n\t" \
-  "popl        %es\n\t" \
-  "popl        %ds\n\t" \
-  "popa\n\t" \
-  "iret\n\t");
-
 #define BUILD_INTERRUPT_HANDLER(intnum) \
-VOID INT_NAME2(intnum)(VOID); \
-__asm__( \
-  STR(INT_NAME(intnum)) ":\n\t" \
-  "pusha\n\t" \
-  "movl $0x" STR(intnum) ",%ebx\n\t" \
-  "jmp _KiCommonInterrupt");
-
+VOID INT_NAME2(intnum)(VOID);
 
-/* Interrupt handlers and declarations */
-
-#define B(x,y) \
+#define D(x,y) \
   BUILD_INTERRUPT_HANDLER(x##y)
 
-#define B16(x) \
-  B(x,0) B(x,1) B(x,2) B(x,3) \
-  B(x,4) B(x,5) B(x,6) B(x,7) \
-  B(x,8) B(x,9) B(x,A) B(x,B) \
-  B(x,C) B(x,D) B(x,E) B(x,F)
-
-
-BUILD_COMMON_INTERRUPT_HANDLER()
-B16(3) B16(4) B16(5) B16(6)
-B16(7) B16(8) B16(9) B16(A)
-B16(B) B16(C) B16(D) B16(E)
-B16(F)
+#define D16(x) \
+  D(x,0) D(x,1) D(x,2) D(x,3) \
+  D(x,4) D(x,5) D(x,6) D(x,7) \
+  D(x,8) D(x,9) D(x,A) D(x,B) \
+  D(x,C) D(x,D) D(x,E) D(x,F)
 
-#undef B
-#undef B16
-
-
-/* Interrupt handler list */
+D16(3) D16(4) D16(5) D16(6)
+D16(7) D16(8) D16(9) D16(A)
+D16(B) D16(C) D16(D) D16(E)
+D16(F)
 
 #define L(x,y) \
   (ULONG)& INT_NAME2(x##y)
 
 #define L16(x) \
-       L(x,0), L(x,1), L(x,2), L(x,3), \
-       L(x,4), L(x,5), L(x,6), L(x,7), \
-       L(x,8), L(x,9), L(x,A), L(x,B), \
-       L(x,C), L(x,D), L(x,E), L(x,F)
+        L(x,0), L(x,1), L(x,2), L(x,3), \
+        L(x,4), L(x,5), L(x,6), L(x,7), \
+        L(x,8), L(x,9), L(x,A), L(x,B), \
+        L(x,C), L(x,D), L(x,E), L(x,F)
 
-static ULONG irq_handler[NR_IRQS] = {
+static ULONG irq_handler[ROUND_UP(NR_IRQS, 16)] = {
   L16(3), L16(4), L16(5), L16(6),
   L16(7), L16(8), L16(9), L16(A),
-  L16(B), L16(C), L16(D), L16(E),
-  L16(F)
+  L16(B), L16(C), L16(D), L16(E)
 };
 
 #undef L
 #undef L16
-
-#else /* MP */
-
-#define NR_IRQS         (16)
-#define IRQ_BASE        (0x40)
-
- void irq_handler_0(void);
- void irq_handler_1(void);
- void irq_handler_2(void);
- void irq_handler_3(void);
- void irq_handler_4(void);
- void irq_handler_5(void);
- void irq_handler_6(void);
- void irq_handler_7(void);
- void irq_handler_8(void);
- void irq_handler_9(void);
- void irq_handler_10(void);
- void irq_handler_11(void);
- void irq_handler_12(void);
- void irq_handler_13(void);
- void irq_handler_14(void);
- void irq_handler_15(void);
+#undef D
+#undef D16
+
+#else /* CONFIG_SMP */
+
+void irq_handler_0(void);
+void irq_handler_1(void);
+void irq_handler_2(void);
+void irq_handler_3(void);
+void irq_handler_4(void);
+void irq_handler_5(void);
+void irq_handler_6(void);
+void irq_handler_7(void);
+void irq_handler_8(void);
+void irq_handler_9(void);
+void irq_handler_10(void);
+void irq_handler_11(void);
+void irq_handler_12(void);
+void irq_handler_13(void);
+void irq_handler_14(void);
+void irq_handler_15(void);
 
 static unsigned int irq_handler[NR_IRQS]=
-        {
-                (int)&irq_handler_0,
-                (int)&irq_handler_1,
-                (int)&irq_handler_2,
-                (int)&irq_handler_3,
-                (int)&irq_handler_4,
-                (int)&irq_handler_5,
-                (int)&irq_handler_6,
-                (int)&irq_handler_7,
-                (int)&irq_handler_8,
-                (int)&irq_handler_9,
-                (int)&irq_handler_10,
-                (int)&irq_handler_11,
-                (int)&irq_handler_12,
-                (int)&irq_handler_13,
-                (int)&irq_handler_14,
-                (int)&irq_handler_15,
-        };
-
-#endif /* MP */
+{
+   (int)&irq_handler_0,
+   (int)&irq_handler_1,
+   (int)&irq_handler_2,
+   (int)&irq_handler_3,
+   (int)&irq_handler_4,
+   (int)&irq_handler_5,
+   (int)&irq_handler_6,
+   (int)&irq_handler_7,
+   (int)&irq_handler_8,
+   (int)&irq_handler_9,
+   (int)&irq_handler_10,
+   (int)&irq_handler_11,
+   (int)&irq_handler_12,
+   (int)&irq_handler_13,
+   (int)&irq_handler_14,
+   (int)&irq_handler_15,
+};
+
+#endif /* CONFIG_SMP */
 
 /*
- * PURPOSE: Object describing each isr 
+ * PURPOSE: Object describing each isr
  * NOTE: The data in this table is only modified at passsive level but can
  * be accessed at any irq level.
  */
 
-static LIST_ENTRY isr_table[NR_IRQS]={{NULL,NULL},};
-static PKSPIN_LOCK isr_lock[NR_IRQS] = {NULL,};
-static KSPIN_LOCK isr_table_lock = {0,};
+typedef struct
+{
+   LIST_ENTRY ListHead;
+   KSPIN_LOCK Lock;
+   ULONG Count;
+}
+ISR_TABLE, *PISR_TABLE;
+
+#ifdef CONFIG_SMP
+static ISR_TABLE IsrTable[NR_IRQS][MAXIMUM_PROCESSORS];
+#else
+static ISR_TABLE IsrTable[NR_IRQS][1];
+#endif
 
 #define TAG_ISR_LOCK     TAG('I', 'S', 'R', 'L')
-#define TAG_KINTERRUPT   TAG('K', 'I', 'S', 'R')
+extern IDT_DESCRIPTOR KiIdt[256];
 
 /* FUNCTIONS ****************************************************************/
 
 #define PRESENT (0x8000)
 #define I486_INTERRUPT_GATE (0xe00)
 
-VOID KeInitInterrupts (VOID)
+VOID
+INIT_FUNCTION
+NTAPI
+KeInitInterrupts (VOID)
 {
-   int i;
+   int i, j;
 
-#ifdef MP
 
    /*
     * Setup the IDT entries to point to the interrupt handlers
     */
    for (i=0;i<NR_IRQS;i++)
      {
-       KiIdt[0x30+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
-       KiIdt[0x30+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
-                           I486_INTERRUPT_GATE;
-       InitializeListHead(&isr_table[i]);
-     }
-
+        KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KGDT_R0_CODE<<16);
+        KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
+                            I486_INTERRUPT_GATE;
+#ifdef CONFIG_SMP
+        for (j = 0; j < MAXIMUM_PROCESSORS; j++)
 #else
-
-   /*
-    * Setup the IDT entries to point to the interrupt handlers
-    */
-   for (i=0;i<NR_IRQS;i++)
-     {
-       KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
-       KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
-                           I486_INTERRUPT_GATE;
-       InitializeListHead(&isr_table[i]);
-     }
-
+        j = 0;
 #endif
-
+          {
+            InitializeListHead(&IsrTable[i][j].ListHead);
+            KeInitializeSpinLock(&IsrTable[i][j].Lock);
+            IsrTable[i][j].Count = 0;
+          }
+     }
 }
 
-typedef struct _KIRQ_TRAPFRAME
-{
-   ULONG Magic;
-   ULONG Fs;
-   ULONG Es;
-   ULONG Ds;
-   ULONG Eax;
-   ULONG Ecx;
-   ULONG Edx;
-   ULONG Ebx;
-   ULONG Esp;
-   ULONG Ebp;
-   ULONG Esi;
-   ULONG Edi;
-   ULONG Eip;
-   ULONG Cs;
-   ULONG Eflags;
-} KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
-
-#ifdef DBG
-
-VOID
+STATIC VOID
 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
-  PKTRAP_FRAME TrapFrame)
+                          PKTRAP_FRAME TrapFrame)
 {
-   TrapFrame->Fs     = IrqTrapFrame->Fs;
-   TrapFrame->Fs     = IrqTrapFrame->Es;
-   TrapFrame->Ds     = IrqTrapFrame->Ds;
+   TrapFrame->SegGs     = (USHORT)IrqTrapFrame->Gs;
+   TrapFrame->SegFs     = (USHORT)IrqTrapFrame->Fs;
+   TrapFrame->SegEs     = (USHORT)IrqTrapFrame->Es;
+   TrapFrame->SegDs     = (USHORT)IrqTrapFrame->Ds;
    TrapFrame->Eax    = IrqTrapFrame->Eax;
    TrapFrame->Ecx    = IrqTrapFrame->Ecx;
    TrapFrame->Edx    = IrqTrapFrame->Edx;
    TrapFrame->Ebx    = IrqTrapFrame->Ebx;
-   TrapFrame->Esp    = IrqTrapFrame->Esp;
+   TrapFrame->HardwareEsp    = IrqTrapFrame->Esp;
    TrapFrame->Ebp    = IrqTrapFrame->Ebp;
    TrapFrame->Esi    = IrqTrapFrame->Esi;
    TrapFrame->Edi    = IrqTrapFrame->Edi;
    TrapFrame->Eip    = IrqTrapFrame->Eip;
-   TrapFrame->Cs     = IrqTrapFrame->Cs;
-   TrapFrame->Eflags = IrqTrapFrame->Eflags;
+   TrapFrame->SegCs     = IrqTrapFrame->Cs;
+   TrapFrame->EFlags = IrqTrapFrame->Eflags;
 }
 
-#endif
-
-#ifdef MP
+STATIC VOID
+KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
+                          PKIRQ_TRAPFRAME IrqTrapFrame)
+{
+   IrqTrapFrame->Gs     = TrapFrame->SegGs;
+   IrqTrapFrame->Fs     = TrapFrame->SegFs;
+   IrqTrapFrame->Es     = TrapFrame->SegEs;
+   IrqTrapFrame->Ds     = TrapFrame->SegDs;
+   IrqTrapFrame->Eax    = TrapFrame->Eax;
+   IrqTrapFrame->Ecx    = TrapFrame->Ecx;
+   IrqTrapFrame->Edx    = TrapFrame->Edx;
+   IrqTrapFrame->Ebx    = TrapFrame->Ebx;
+   IrqTrapFrame->Esp    = TrapFrame->HardwareEsp;
+   IrqTrapFrame->Ebp    = TrapFrame->Ebp;
+   IrqTrapFrame->Esi    = TrapFrame->Esi;
+   IrqTrapFrame->Edi    = TrapFrame->Edi;
+   IrqTrapFrame->Eip    = TrapFrame->Eip;
+   IrqTrapFrame->Cs     = TrapFrame->SegCs;
+   IrqTrapFrame->Eflags = TrapFrame->EFlags;
+}
 
-VOID
-KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
+VOID STDCALL
+KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
 /*
- * FUNCTION: Calls the irq specific handler for an irq
+ * FUNCTION: Calls all the interrupt handlers for a given irq.
  * ARGUMENTS:
- *         Vector    = Interrupt vector
- *         Trapframe = CPU context
+ *        vector - The number of the vector to call handlers for.
+ *        old_level - The irql of the processor when the irq took place.
+ * NOTES: Must be called at DIRQL.
  */
 {
-   KIRQL old_level;
-   PKINTERRUPT isr;
-   PLIST_ENTRY current;
-   ULONG irq;
-
-#ifdef DBG
-
-   KTRAP_FRAME KernelTrapFrame;
-
-   KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
-   KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
-
-#endif /* DBG */
-
-   DPRINT("I(%d) ", Vector);
-
-   /*
-    * Notify the rest of the kernel of the raised irq level
-    */
-   HalBeginSystemInterrupt (Vector,
-                           VECTOR2IRQL(Vector),
-                           &old_level);
-
-   irq = VECTOR2IRQ(Vector);
-
-   /*
-    * Enable interrupts
-    * NOTE: Only higher priority interrupts will get through
-    */
-   __asm__("sti\n\t");
-
-   if (irq == 0)
-     {
-       if (KeGetCurrentProcessorNumber() == 0)
-         {
-       KiUpdateSystemTime(old_level, Trapframe->Eip);
-         }
-     }
-   else
-     {
-      DPRINT("KiInterruptDispatch(Vector %d)\n", Vector);
-      /*
-       * Iterate the list until one of the isr tells us its device interrupted
-       */
-      current = isr_table[irq].Flink;
-      isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
-      //DPRINT("current %x isr %x\n",current,isr);
-      while (current!=(&isr_table[irq]) && 
-            !isr->ServiceRoutine(isr,isr->ServiceContext))
-       {
-          current = current->Flink;
-          isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
-          //DPRINT("current %x isr %x\n",current,isr);
-       }
-    }
-   /*
-    * Disable interrupts
-    */
-   __asm__("cli\n\t");
-
-   /*
-    * Unmask the related irq
-    */
-   HalEnableSystemInterrupt (Vector, 0, 0);
-
-   /*
-    * If the processor level will drop below dispatch level on return then
-    * issue a DPC queue drain interrupt
-    */
-
-   __asm__("sti\n\t");
+  PKINTERRUPT isr;
+  PLIST_ENTRY current;
+  KIRQL oldlvl;
+  PISR_TABLE CurrentIsr;
 
-   if (old_level < DISPATCH_LEVEL)
-     {
+  DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
 
-  HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
-
-       if (KeGetCurrentThread() != NULL)
-         {
-            KeGetCurrentThread()->LastEip = Trapframe->Eip;
-         }
-       KiDispatchInterrupt();
-       if (KeGetCurrentThread() != NULL &&
-           KeGetCurrentThread()->Alerted[1] != 0 &&
-           Trapframe->Cs != KERNEL_CS)
-         {
-           HalEndSystemInterrupt (APC_LEVEL, 0);
-           KiDeliverNormalApc();
-         }
-    }
+  /*
+   * Iterate the list until one of the isr tells us its device interrupted
+   */
+  CurrentIsr = &IsrTable[vector - IRQ_BASE][(ULONG)KeGetCurrentProcessorNumber()];
 
-  HalEndSystemInterrupt (old_level, 0);
-}
+  KiAcquireSpinLock(&CurrentIsr->Lock);
 
-#else /* MP */
+  CurrentIsr->Count++;
+  current = CurrentIsr->ListHead.Flink;
 
-VOID STDCALL
-KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
-{
-  PKINTERRUPT isr;
-  PLIST_ENTRY current;
-
-  if (Irq == 0)
+  while (current != &CurrentIsr->ListHead)
     {
-      KiUpdateSystemTime(old_level, 0);
+      isr = CONTAINING_RECORD(current,KINTERRUPT,InterruptListEntry);
+      oldlvl = KeAcquireInterruptSpinLock(isr);
+      if (isr->ServiceRoutine(isr, isr->ServiceContext))
+        {
+          KeReleaseInterruptSpinLock(isr, oldlvl);
+          break;
+        }
+      KeReleaseInterruptSpinLock(isr, oldlvl);
+      current = current->Flink;
     }
-  else
-    {
-      /*
-       * Iterate the list until one of the isr tells us its device interrupted
-       */
-      current = isr_table[Irq].Flink;
-      isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
-      while (current != &isr_table[Irq] && 
-            !isr->ServiceRoutine(isr, isr->ServiceContext))
-       {
-         current = current->Flink;
-         isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
-       }
-   }
+  KiReleaseSpinLock(&CurrentIsr->Lock);
 }
 
-VOID 
-KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
+VOID
+KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
 /*
  * FUNCTION: Calls the irq specific handler for an irq
  * ARGUMENTS:
@@ -406,295 +260,327 @@ KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
  */
 {
    KIRQL old_level;
-   static ULONG Irq0Count = 0;
-
-#if 0
    KTRAP_FRAME KernelTrapFrame;
-
-   KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
-   KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
-#endif /* DBG */
-
-   if (InterlockedIncrement(&Irq0Count) > 32)
-     {
-       __asm__("int $3\n\t");
-     }
+   PKTHREAD CurrentThread;
+   PKTRAP_FRAME OldTrapFrame=NULL;
 
    /*
     * At this point we have interrupts disabled, nothing has been done to
     * the PIC.
     */
 
+   KeGetCurrentPrcb()->InterruptCount++;
+
    /*
     * Notify the rest of the kernel of the raised irq level. For the
     * default HAL this will send an EOI to the PIC and alter the IRQL.
     */
-   if (!HalBeginSystemInterrupt (irq + IRQ_BASE,
-                                PROFILE_LEVEL - irq,
-                                &old_level))
+   if (!HalBeginSystemInterrupt (vector,
+                                 VECTOR2IRQL(vector),
+                                 &old_level))
      {
-       InterlockedDecrement(&Irq0Count);
        return;
      }
 
+
    /*
     * Enable interrupts
     * NOTE: Only higher priority interrupts will get through
     */
-   __asm__("sti\n\t");
+   Ke386EnableInterrupts();
 
-   /*
-    * Actually call the ISR.
-    */
-   KiInterruptDispatch2(irq, old_level);
+#ifndef CONFIG_SMP
+   if (VECTOR2IRQ(vector) == 0)
+   {
+      KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
+      KeUpdateSystemTime(&KernelTrapFrame, old_level);
+   }
+   else
+#endif
+   {
+     /*
+      * Actually call the ISR.
+      */
+     KiInterruptDispatch2(vector, old_level);
+   }
 
    /*
     * End the system interrupt.
     */
-   HalEndSystemInterrupt (old_level, 0);
+   Ke386DisableInterrupts();
 
-   InterlockedDecrement(&Irq0Count);
+   if (old_level==PASSIVE_LEVEL && Trapframe->Cs != KGDT_R0_CODE)
+     {
+       HalEndSystemInterrupt (APC_LEVEL, 0);
 
-   if (old_level < DISPATCH_LEVEL && irq == 0)
+       CurrentThread = KeGetCurrentThread();
+       if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending)
+         {
+           DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
+                  ((PETHREAD)CurrentThread)->ThreadsProcess->UniqueProcessId,
+                  ((PETHREAD)CurrentThread)->Cid.UniqueThread,
+                  Trapframe->Cs,
+                  CurrentThread->TrapFrame ? CurrentThread->TrapFrame->Cs : 0);
+           if (CurrentThread->TrapFrame == NULL)
+             {
+               OldTrapFrame = CurrentThread->TrapFrame;
+               KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
+               CurrentThread->TrapFrame = &KernelTrapFrame;
+             }
+
+           Ke386EnableInterrupts();
+           KiDeliverApc(UserMode, NULL, NULL);
+           Ke386DisableInterrupts();
+
+           ASSERT(KeGetCurrentThread() == CurrentThread);
+           if (CurrentThread->TrapFrame == &KernelTrapFrame)
+             {
+               KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
+               CurrentThread->TrapFrame = OldTrapFrame;
+             }
+         }
+       KeLowerIrql(PASSIVE_LEVEL);
+     }
+   else
      {
-       PsDispatchThread(THREAD_STATE_RUNNABLE);
+       HalEndSystemInterrupt (old_level, 0);
      }
-}
 
-#endif /* MP */
+}
 
-static VOID 
+static VOID
 KeDumpIrqList(VOID)
 {
    PKINTERRUPT current;
    PLIST_ENTRY current_entry;
-   unsigned int i;
-   
+   LONG i, j;
+   KIRQL oldlvl;
+   BOOLEAN printed;
+
    for (i=0;i<NR_IRQS;i++)
      {
-       DPRINT("For irq %x ",i);
-       current_entry = isr_table[i].Flink;
-       current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
-       while (current_entry!=(&isr_table[i]))
-         {
-            DPRINT("Isr %x ",current);
-            current_entry = current_entry->Flink;
-            current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
-         }
-       DPRINT("\n",0);
+        printed = FALSE;
+        KeRaiseIrql(VECTOR2IRQL(i + IRQ_BASE),&oldlvl);
+
+        for (j=0; j < KeNumberProcessors; j++)
+          {
+            KiAcquireSpinLock(&IsrTable[i][j].Lock);
+
+            current_entry = IsrTable[i][j].ListHead.Flink;
+            current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
+            while (current_entry!=&(IsrTable[i][j].ListHead))
+              {
+                if (printed == FALSE)
+                  {
+                    printed = TRUE;
+                    DPRINT("For irq %x:\n",i);
+                  }
+                DPRINT("   Isr %x\n",current);
+                current_entry = current_entry->Flink;
+                current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
+              }
+            KiReleaseSpinLock(&IsrTable[i][j].Lock);
+          }
+        KeLowerIrql(oldlvl);
      }
 }
 
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+BOOLEAN 
+STDCALL
 KeConnectInterrupt(PKINTERRUPT InterruptObject)
 {
-   KIRQL oldlvl;
-   KIRQL synch_oldlvl;
+   KIRQL oldlvl,synch_oldlvl;
    PKINTERRUPT ListHead;
    ULONG Vector;
+   PISR_TABLE CurrentIsr;
+   BOOLEAN Result;
 
    DPRINT("KeConnectInterrupt()\n");
 
    Vector = InterruptObject->Vector;
 
-   /*
-    * Acquire the table spinlock
-    */
-   KeAcquireSpinLock(&isr_table_lock,&oldlvl);
-   
+   if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
+      return FALSE;
+
+   Vector -= IRQ_BASE;
+
+   ASSERT (InterruptObject->Number < KeNumberProcessors);
+
+   KeSetSystemAffinityThread(1 << InterruptObject->Number);
+
+   CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number];
+
+   KeRaiseIrql(VECTOR2IRQL(Vector + IRQ_BASE),&oldlvl);
+   KiAcquireSpinLock(&CurrentIsr->Lock);
+
    /*
     * Check if the vector is already in use that we can share it
     */
-   ListHead = CONTAINING_RECORD(isr_table[Vector].Flink,KINTERRUPT,Entry);
-   if (!IsListEmpty(&isr_table[Vector]) &&
-       (InterruptObject->Shareable == FALSE || ListHead->Shareable==FALSE))
-     {
-       KeReleaseSpinLock(&isr_table_lock,oldlvl);
-       return(STATUS_INVALID_PARAMETER);
-     }
-   else
-     {
-       isr_lock[Vector] =
-         ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK),
-                               TAG_ISR_LOCK);
-       KeInitializeSpinLock(isr_lock[Vector]);
-     }
+   if (!IsListEmpty(&CurrentIsr->ListHead))
+   {
+      ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,InterruptListEntry);
+      if (InterruptObject->ShareVector == FALSE || ListHead->ShareVector==FALSE)
+      {
+         KiReleaseSpinLock(&CurrentIsr->Lock);
+         KeLowerIrql(oldlvl);
+         KeRevertToUserAffinityThread();
+         return FALSE;
+      }
+   }
+
+   synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
+
+   DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
+
+   Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->Mode);
+   if (Result)
+   {
+      InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
+      DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
+   }
+
+   InterruptObject->Connected = TRUE;
+   KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
 
-   InterruptObject->IrqLock = isr_lock[Vector];
-
-   KeRaiseIrql(InterruptObject->SynchLevel,&synch_oldlvl);
-   KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
-   DPRINT("%x %x\n",isr_table[Vector].Flink,isr_table[Vector].Blink);
-   InsertTailList(&isr_table[Vector],&InterruptObject->Entry);
-   DPRINT("%x %x\n",InterruptObject->Entry.Flink,
-          InterruptObject->Entry.Blink);
-   KeReleaseSpinLockFromDpcLevel(InterruptObject->IrqLock);
-   KeLowerIrql(synch_oldlvl);
-   
    /*
     * Release the table spinlock
     */
-   KeReleaseSpinLock(&isr_table_lock,oldlvl);
-   
+   KiReleaseSpinLock(&CurrentIsr->Lock);
+   KeLowerIrql(oldlvl);
+
    KeDumpIrqList();
 
-   return STATUS_SUCCESS;
-}
+   KeRevertToUserAffinityThread();
 
+   return Result;
+}
 
-VOID STDCALL
-KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
 /*
+ * @implemented
+ *
  * FUNCTION: Releases a drivers isr
  * ARGUMENTS:
  *        InterruptObject = isr to release
  */
-{
-   KIRQL oldlvl;
-   
-   KeRaiseIrql(InterruptObject->SynchLevel,&oldlvl);
-   KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
-   RemoveEntryList(&InterruptObject->Entry);
-   KeReleaseSpinLockFromDpcLevel(InterruptObject->IrqLock);
-   KeLowerIrql(oldlvl);
-}
-
-
-NTSTATUS
+BOOLEAN 
 STDCALL
-KeInitializeInterrupt(PKINTERRUPT InterruptObject,
-                     PKSERVICE_ROUTINE ServiceRoutine,
-                     PVOID ServiceContext,
-                     PKSPIN_LOCK SpinLock,
-                     ULONG Vector,
-                     KIRQL Irql,
-                     KIRQL SynchronizeIrql,
-                     KINTERRUPT_MODE InterruptMode,
-                     BOOLEAN ShareVector,
-                     KAFFINITY ProcessorEnableMask,
-                     BOOLEAN FloatingSave)
+KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
 {
-   InterruptObject->ServiceContext = ServiceContext;
-   InterruptObject->ServiceRoutine = ServiceRoutine;
-   InterruptObject->Vector = Vector;
-   InterruptObject->ProcessorEnableMask = ProcessorEnableMask;
-   InterruptObject->SynchLevel = SynchronizeIrql;
-   InterruptObject->Shareable = ShareVector;
-   InterruptObject->FloatingSave = FALSE;
-
-   return STATUS_SUCCESS;
-}
+    KIRQL oldlvl,synch_oldlvl;
+    PISR_TABLE CurrentIsr;
+    BOOLEAN State;
 
+    DPRINT1("KeDisconnectInterrupt\n");
+    ASSERT (InterruptObject->Number < KeNumberProcessors);
 
-NTSTATUS STDCALL
-IoConnectInterrupt(PKINTERRUPT* InterruptObject,
-                  PKSERVICE_ROUTINE ServiceRoutine,
-                  PVOID ServiceContext,
-                  PKSPIN_LOCK SpinLock,
-                  ULONG Vector,
-                  KIRQL Irql,
-                  KIRQL SynchronizeIrql,
-                  KINTERRUPT_MODE InterruptMode,
-                  BOOLEAN ShareVector,
-                  KAFFINITY ProcessorEnableMask,
-                  BOOLEAN FloatingSave)
-/*
- * FUNCTION: Registers a driver's isr to be called when its device interrupts
- * ARGUMENTS:
- *        InterruptObject (OUT) = Points to the interrupt object created on 
- *                                return
- *        ServiceRoutine = Routine to be called when the device interrupts
- *        ServiceContext = Parameter to be passed to ServiceRoutine
- *        SpinLock = Initalized spinlock that will be used to synchronize
- *                   access between the isr and other driver routines. This is
- *                   required if the isr handles more than one vector or the
- *                   driver has more than one isr
- *        Vector = Interrupt vector to allocate 
- *                 (returned from HalGetInterruptVector)
- *        Irql = DIRQL returned from HalGetInterruptVector
- *        SynchronizeIrql = DIRQL at which the isr will execute. This must
- *                          be the highest of all the DIRQLs returned from
- *                          HalGetInterruptVector if the driver has multiple
- *                          isrs
- *        InterruptMode = Specifies if the interrupt is LevelSensitive or
- *                        Latched
- *        ShareVector = Specifies if the vector can be shared
- *        ProcessorEnableMask = Processors on the isr can run
- *        FloatingSave = TRUE if the floating point stack should be saved when
- *                       the isr runs. Must be false for x86 drivers
- * RETURNS: Status
- * IRQL: PASSIVE_LEVEL
- */
-{
-   PKINTERRUPT Interrupt;
-   NTSTATUS Status = STATUS_SUCCESS;
-   
-   ASSERT_IRQL(PASSIVE_LEVEL);
-   
-   DPRINT("IoConnectInterrupt(Vector %x)\n",Vector);
-   
-   /*
-    * Check the parameters
-    */
-   if (Vector >= NR_IRQS)
-     {
-       return(STATUS_INVALID_PARAMETER);
-     }
-   if (FloatingSave == TRUE)
-     {
-       return(STATUS_INVALID_PARAMETER);
-     }
-   
-   /*
-    * Initialize interrupt object
-    */
-   Interrupt=ExAllocatePoolWithTag(NonPagedPool,sizeof(KINTERRUPT),
-                                  TAG_KINTERRUPT);
-   if (Interrupt==NULL)
-     {
-       return(STATUS_INSUFFICIENT_RESOURCES);
-     }
+    /* Set the affinity */
+    KeSetSystemAffinityThread(1 << InterruptObject->Number);
 
-   Status = KeInitializeInterrupt(Interrupt,
-                                 ServiceRoutine,
-                                 ServiceContext,
-                                 SpinLock,
-                                 Vector,
-                                 Irql,
-                                 SynchronizeIrql,
-                                 InterruptMode,
-                                 ShareVector,
-                                 ProcessorEnableMask,
-                                 FloatingSave);
-   if (!NT_SUCCESS(Status))
-     {
-       ExFreePool(Interrupt);
-       return Status;
-     }
+    /* Get the ISR Tabe */
+    CurrentIsr = &IsrTable[InterruptObject->Vector - IRQ_BASE]
+                          [(ULONG)InterruptObject->Number];
 
-   Status = KeConnectInterrupt(Interrupt);
-   if (!NT_SUCCESS(Status))
-     {
-       ExFreePool(Interrupt);
-       return Status;
-     }
+    /* Raise IRQL to required level and lock table */
+    KeRaiseIrql(VECTOR2IRQL(InterruptObject->Vector),&oldlvl);
+    KiAcquireSpinLock(&CurrentIsr->Lock);
 
-   *InterruptObject = Interrupt;
+    /* Check if it's actually connected */
+    if ((State = InterruptObject->Connected))
+    {
+        /* Lock the Interrupt */
+        synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
 
-   return(STATUS_SUCCESS);
+        /* Remove this one, and check if all are gone */
+        RemoveEntryList(&InterruptObject->InterruptListEntry);
+        if (IsListEmpty(&CurrentIsr->ListHead))
+        {
+            /* Completely Disable the Interrupt */
+            HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql);
+        }
+        
+        /* Disconnect it */
+        InterruptObject->Connected = FALSE;
+    
+        /* Release the interrupt lock */
+        KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
+    }
+    /* Release the table spinlock */
+    KiReleaseSpinLock(&CurrentIsr->Lock);
+    KeLowerIrql(oldlvl);
+
+    /* Go back to default affinity */
+    KeRevertToUserAffinityThread();
+    
+    /* Return Old Interrupt State */
+    return State;
 }
 
-
-VOID STDCALL
-IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
 /*
- * FUNCTION: Releases a drivers isr
- * ARGUMENTS:
- *        InterruptObject = isr to release
+ * @implemented
  */
+VOID
+STDCALL
+KeInitializeInterrupt(PKINTERRUPT Interrupt,
+                      PKSERVICE_ROUTINE ServiceRoutine,
+                      PVOID ServiceContext,
+                      PKSPIN_LOCK SpinLock,
+                      ULONG Vector,
+                      KIRQL Irql,
+                      KIRQL SynchronizeIrql,
+                      KINTERRUPT_MODE InterruptMode,
+                      BOOLEAN ShareVector,
+                      CHAR ProcessorNumber,
+                      BOOLEAN FloatingSave)
 {
-  KeDisconnectInterrupt(InterruptObject);
-  ExFreePool(InterruptObject);
+    /* Set the Interrupt Header */
+    Interrupt->Type = InterruptObject;
+    Interrupt->Size = sizeof(KINTERRUPT);
+    
+    /* Check if we got a spinlock */
+    if (SpinLock)
+    {
+        Interrupt->ActualLock = SpinLock;
+    }
+    else
+    {
+        /* This means we'll be usin the built-in one */
+        KeInitializeSpinLock(&Interrupt->SpinLock);
+        Interrupt->ActualLock = &Interrupt->SpinLock;
+    }
+    
+    /* Set the other settings */
+    Interrupt->ServiceRoutine = ServiceRoutine;
+    Interrupt->ServiceContext = ServiceContext;
+    Interrupt->Vector = Vector;
+    Interrupt->Irql = Irql;
+    Interrupt->SynchronizeIrql = SynchronizeIrql;
+    Interrupt->Mode = InterruptMode;
+    Interrupt->ShareVector = ShareVector;
+    Interrupt->Number = ProcessorNumber;
+    Interrupt->FloatingSave = FloatingSave;
+    
+    /* Disconnect it at first */
+    Interrupt->Connected = FALSE;
+}
+
+VOID KePrintInterruptStatistic(VOID)
+{
+   LONG i, j;
+
+   for (j = 0; j < KeNumberProcessors; j++)
+   {
+      DPRINT1("CPU%d:\n", j);
+      for (i = 0; i < NR_IRQS; i++)
+      {
+         if (IsrTable[i][j].Count)
+         {
+             DPRINT1("  Irq %x(%d): %d\n", i, VECTOR2IRQ(i + IRQ_BASE), IsrTable[i][j].Count);
+         }
+      }
+   }
 }
 
 /* EOF */