-/* $Id: irq.c,v 1.8 2001/03/16 16:05:34 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 <internal/ke.h>
-#include <internal/ps.h>
-#include <internal/i386/segment.h>
-#include <internal/pool.h>
+#include <ntoskrnl.h>
+#include <../hal/halx86/include/halirq.h>
+#include <../hal/halx86/include/mps.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *****************************************************************/
-#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);
+/* Interrupt handler list */
+
+#ifdef CONFIG_SMP
+
+#define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
+
+#define BUILD_INTERRUPT_HANDLER(intnum) \
+VOID INT_NAME2(intnum)(VOID);
+
+#define D(x,y) \
+ BUILD_INTERRUPT_HANDLER(x##y)
+
+#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)
+
+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)
+
+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)
+};
+
+#undef L
+#undef L16
+#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,
- };
+{
+ (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;
-
- DPRINT("KeInitInterrupts ()\n",0);
-
+ int i, j;
+
+
/*
* 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]);
+ 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
+ j = 0;
+#endif
+ {
+ InitializeListHead(&IsrTable[i][j].ListHead);
+ KeInitializeSpinLock(&IsrTable[i][j].Lock);
+ IsrTable[i][j].Count = 0;
+ }
}
}
-typedef struct _KIRQ_TRAPFRAME
+STATIC VOID
+KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
+ PKTRAP_FRAME TrapFrame)
+{
+ 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->HardwareEsp = IrqTrapFrame->Esp;
+ TrapFrame->Ebp = IrqTrapFrame->Ebp;
+ TrapFrame->Esi = IrqTrapFrame->Esi;
+ TrapFrame->Edi = IrqTrapFrame->Edi;
+ TrapFrame->Eip = IrqTrapFrame->Eip;
+ TrapFrame->SegCs = IrqTrapFrame->Cs;
+ TrapFrame->EFlags = IrqTrapFrame->Eflags;
+}
+
+STATIC VOID
+KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
+ PKIRQ_TRAPFRAME IrqTrapFrame)
{
- 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;
-
-VOID
-KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
+ 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 STDCALL
+KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
+/*
+ * FUNCTION: Calls all the interrupt handlers for a given irq.
+ * ARGUMENTS:
+ * 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.
+ */
+{
+ PKINTERRUPT isr;
+ PLIST_ENTRY current;
+ KIRQL oldlvl;
+ PISR_TABLE CurrentIsr;
+
+ DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
+
+ /*
+ * Iterate the list until one of the isr tells us its device interrupted
+ */
+ CurrentIsr = &IsrTable[vector - IRQ_BASE][(ULONG)KeGetCurrentProcessorNumber()];
+
+ KiAcquireSpinLock(&CurrentIsr->Lock);
+
+ CurrentIsr->Count++;
+ current = CurrentIsr->ListHead.Flink;
+
+ while (current != &CurrentIsr->ListHead)
+ {
+ 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;
+ }
+ KiReleaseSpinLock(&CurrentIsr->Lock);
+}
+
+VOID
+KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
/*
* FUNCTION: Calls the irq specific handler for an irq
* ARGUMENTS:
*/
{
KIRQL old_level;
- PKINTERRUPT isr;
- PLIST_ENTRY current;
-
-// DbgPrint("{");
-
+ KTRAP_FRAME KernelTrapFrame;
+ PKTHREAD CurrentThread;
+ PKTRAP_FRAME OldTrapFrame=NULL;
+
/*
- * Notify the rest of the kernel of the raised irq level
+ * At this point we have interrupts disabled, nothing has been done to
+ * the PIC.
*/
- HalBeginSystemInterrupt (irq+IRQ_BASE,
- HIGH_LEVEL-irq,
- &old_level);
-
+
+ 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 (vector,
+ VECTOR2IRQL(vector),
+ &old_level))
+ {
+ return;
+ }
+
+
/*
* Enable interrupts
* NOTE: Only higher priority interrupts will get through
*/
- __asm__("sti\n\t");
+ Ke386EnableInterrupts();
- if (irq==0)
- {
- KiUpdateSystemTime(old_level, Trapframe->Eip);
- }
+#ifndef CONFIG_SMP
+ if (VECTOR2IRQ(vector) == 0)
+ {
+ KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
+ KeUpdateSystemTime(&KernelTrapFrame, old_level);
+ }
else
- {
- DPRINT("KiInterruptDispatch(irq %d)\n",irq);
- /*
- * 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);
- }
+#endif
+ {
+ /*
+ * Actually call the ISR.
+ */
+ KiInterruptDispatch2(vector, old_level);
}
-
- /*
- * Disable interrupts
- */
- __asm__("cli\n\t");
-
- /*
- * Unmask the related irq
- */
- HalEnableSystemInterrupt (irq + IRQ_BASE, 0, 0);
-
+
/*
- * If the processor level will drop below dispatch level on return then
- * issue a DPC queue drain interrupt
+ * End the system interrupt.
*/
- if (old_level < DISPATCH_LEVEL)
+ Ke386DisableInterrupts();
+
+ if (old_level==PASSIVE_LEVEL && Trapframe->Cs != KGDT_R0_CODE)
{
- HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
- __asm__("sti\n\t");
-
- if (KeGetCurrentThread() != NULL)
- {
- KeGetCurrentThread()->LastEip = Trapframe->Eip;
- }
- KiDispatchInterrupt();
- if (irq == 0)
- {
- PsDispatchThread(THREAD_STATE_RUNNABLE);
- }
- if (KeGetCurrentThread() != NULL &&
- KeGetCurrentThread()->Alerted[1] != 0 &&
- Trapframe->Cs != KERNEL_CS)
- {
- HalEndSystemInterrupt (APC_LEVEL, 0);
- KiDeliverNormalApc();
- }
+ HalEndSystemInterrupt (APC_LEVEL, 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
+ {
+ HalEndSystemInterrupt (old_level, 0);
}
- HalEndSystemInterrupt (old_level, 0);
}
-
-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,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 */