mirror of
https://github.com/reactos/reactos.git
synced 2024-10-19 15:41:31 +00:00
5a6adb4f13
Fixed bugs in NtQueryDirectoryObject. Added static library target. svn path=/trunk/; revision=2546
707 lines
17 KiB
C
707 lines
17 KiB
C
/* $Id: irq.c,v 1.16 2002/01/23 23:39:25 chorns Exp $
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
/*
|
|
* NOTE: In general the PIC interrupt priority facilities are used to
|
|
* preserve the NT IRQL semantics, global interrupt disables are only used
|
|
* to keep the PIC in a consistent state
|
|
*
|
|
*/
|
|
|
|
/* 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 */
|
|
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
#ifdef MP
|
|
|
|
#define IRQ_BASE FIRST_DEVICE_VECTOR
|
|
#define NR_IRQS 0x100 - 0x30
|
|
|
|
#define __STR(x) #x
|
|
#define STR(x) __STR(x)
|
|
|
|
#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");
|
|
|
|
|
|
/* Interrupt handlers and declarations */
|
|
|
|
#define B(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)
|
|
|
|
#undef B
|
|
#undef B16
|
|
|
|
|
|
/* Interrupt handler list */
|
|
|
|
#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[NR_IRQS] = {
|
|
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)
|
|
};
|
|
|
|
#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);
|
|
|
|
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 */
|
|
|
|
/*
|
|
* 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,};
|
|
|
|
#define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
|
|
#define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R')
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
#define PRESENT (0x8000)
|
|
#define I486_INTERRUPT_GATE (0xe00)
|
|
|
|
VOID KeInitInterrupts (VOID)
|
|
{
|
|
int i;
|
|
|
|
#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]);
|
|
}
|
|
|
|
#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]);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
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
|
|
KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
|
|
PKTRAP_FRAME TrapFrame)
|
|
{
|
|
TrapFrame->Fs = IrqTrapFrame->Fs;
|
|
TrapFrame->Fs = IrqTrapFrame->Es;
|
|
TrapFrame->Ds = IrqTrapFrame->Ds;
|
|
TrapFrame->Eax = IrqTrapFrame->Eax;
|
|
TrapFrame->Ecx = IrqTrapFrame->Ecx;
|
|
TrapFrame->Edx = IrqTrapFrame->Edx;
|
|
TrapFrame->Ebx = IrqTrapFrame->Ebx;
|
|
TrapFrame->Esp = 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;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef MP
|
|
|
|
VOID
|
|
KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
|
|
/*
|
|
* FUNCTION: Calls the irq specific handler for an irq
|
|
* ARGUMENTS:
|
|
* Vector = Interrupt vector
|
|
* Trapframe = CPU context
|
|
*/
|
|
{
|
|
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
|
|
*/
|
|
if (old_level < DISPATCH_LEVEL)
|
|
{
|
|
|
|
HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
|
|
__asm__("sti\n\t");
|
|
|
|
if (KeGetCurrentThread() != NULL)
|
|
{
|
|
KeGetCurrentThread()->LastEip = Trapframe->Eip;
|
|
}
|
|
KiDispatchInterrupt();
|
|
if (KeGetCurrentThread() != NULL &&
|
|
KeGetCurrentThread()->Alerted[1] != 0 &&
|
|
Trapframe->Cs != KERNEL_CS)
|
|
{
|
|
HalEndSystemInterrupt (APC_LEVEL, 0);
|
|
KiDeliverNormalApc();
|
|
}
|
|
}
|
|
|
|
HalEndSystemInterrupt (old_level, 0);
|
|
}
|
|
|
|
#else /* MP */
|
|
|
|
VOID
|
|
KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
|
|
/*
|
|
* FUNCTION: Calls the irq specific handler for an irq
|
|
* ARGUMENTS:
|
|
* irq = IRQ that has interrupted
|
|
*/
|
|
{
|
|
KIRQL old_level;
|
|
PKINTERRUPT isr;
|
|
PLIST_ENTRY current;
|
|
|
|
#ifdef DBG
|
|
|
|
KTRAP_FRAME KernelTrapFrame;
|
|
|
|
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
|
|
KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
|
|
|
|
#endif /* DBG */
|
|
|
|
/*
|
|
* Notify the rest of the kernel of the raised irq level
|
|
*/
|
|
HalBeginSystemInterrupt (irq + IRQ_BASE,
|
|
PROFILE_LEVEL - irq,
|
|
&old_level);
|
|
|
|
/*
|
|
* Enable interrupts
|
|
* NOTE: Only higher priority interrupts will get through
|
|
*/
|
|
__asm__("sti\n\t");
|
|
|
|
if (irq == 0)
|
|
{
|
|
KiUpdateSystemTime(old_level, Trapframe->Eip);
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
if (old_level < DISPATCH_LEVEL)
|
|
{
|
|
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 (old_level, 0);
|
|
}
|
|
|
|
#endif /* MP */
|
|
|
|
static VOID
|
|
KeDumpIrqList(VOID)
|
|
{
|
|
PKINTERRUPT current;
|
|
PLIST_ENTRY current_entry;
|
|
unsigned int i;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS STDCALL
|
|
KeConnectInterrupt(PKINTERRUPT InterruptObject)
|
|
{
|
|
KIRQL oldlvl;
|
|
KIRQL synch_oldlvl;
|
|
PKINTERRUPT ListHead;
|
|
ULONG Vector;
|
|
|
|
DPRINT("KeConnectInterrupt()\n");
|
|
|
|
Vector = InterruptObject->Vector;
|
|
|
|
/*
|
|
* Acquire the table spinlock
|
|
*/
|
|
KeAcquireSpinLock(&isr_table_lock,&oldlvl);
|
|
|
|
/*
|
|
* 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]);
|
|
}
|
|
|
|
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);
|
|
|
|
KeDumpIrqList();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID STDCALL
|
|
KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
|
|
/*
|
|
* 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
|
|
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)
|
|
{
|
|
InterruptObject->ServiceContext = ServiceContext;
|
|
InterruptObject->ServiceRoutine = ServiceRoutine;
|
|
InterruptObject->Vector = Vector;
|
|
InterruptObject->ProcessorEnableMask = ProcessorEnableMask;
|
|
InterruptObject->SynchLevel = SynchronizeIrql;
|
|
InterruptObject->Shareable = ShareVector;
|
|
InterruptObject->FloatingSave = FALSE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
Status = KeInitializeInterrupt(Interrupt,
|
|
ServiceRoutine,
|
|
ServiceContext,
|
|
SpinLock,
|
|
Vector,
|
|
Irql,
|
|
SynchronizeIrql,
|
|
InterruptMode,
|
|
ShareVector,
|
|
ProcessorEnableMask,
|
|
FloatingSave);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(Interrupt);
|
|
return Status;
|
|
}
|
|
|
|
Status = KeConnectInterrupt(Interrupt);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(Interrupt);
|
|
return Status;
|
|
}
|
|
|
|
*InterruptObject = Interrupt;
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID STDCALL
|
|
IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
|
|
/*
|
|
* FUNCTION: Releases a drivers isr
|
|
* ARGUMENTS:
|
|
* InterruptObject = isr to release
|
|
*/
|
|
{
|
|
KeDisconnectInterrupt(InterruptObject);
|
|
ExFreePool(InterruptObject);
|
|
}
|
|
|
|
/* EOF */
|