📄 isrdpc.c
字号:
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
IsrDpc.c
Abstract:
Contains routines related to interrupt and dpc handling.
Environment:
Kernel mode
--*/
#include "precomp.h"
#include "IsrDpc.tmh"
void PCIEWait(int ms);
NTSTATUS
PCIEInterruptCreate(
IN PDEVICE_EXTENSION DevExt
)
/*++
Routine Description:
Configure and create the WDFINTERRUPT object.
This routine is called by EvtDeviceAdd callback.
Arguments:
DevExt Pointer to our DEVICE_EXTENSION
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status;
WDF_INTERRUPT_CONFIG InterruptConfig;
WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig,
PCIEEvtInterruptIsr,
PCIEEvtInterruptDpc );
InterruptConfig.EvtInterruptEnable = PCIEEvtInterruptEnable;
InterruptConfig.EvtInterruptDisable = PCIEEvtInterruptDisable;
// JOHNR: Enable testing of the DpcForIsr Synchronization
InterruptConfig.AutomaticSerialization = TRUE;
//
// Unlike WDM, framework driver should create interrupt object in EvtDeviceAdd and
// let the framework do the resource parsing and registration of ISR with the kernel.
// Framework connects the interrupt after invoking the EvtDeviceD0Entry callback
// and disconnect before invoking EvtDeviceD0Exit. EvtInterruptEnable is called after
// the interrupt interrupt is connected and EvtInterruptDisable before the interrupt is
// disconnected.
//
status = WdfInterruptCreate( DevExt->Device,
&InterruptConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&DevExt->Interrupt );
if( !NT_SUCCESS(status) )
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"WdfInterruptCreate failed: %!STATUS!", status);
KdPrint(("PCIEInterruptCreate: Failed: %x", status));
}
KdPrint(("PCIEInterruptCreate: OK"));
return status;
}
BOOLEAN
PCIEEvtInterruptIsr(
IN WDFINTERRUPT Interrupt,
IN ULONG MessageID
)
/*++
Routine Description:
Interrupt handler for this driver. Called at DIRQL level when the
device or another device sharing the same interrupt line asserts
the interrupt. The driver first checks the device to make sure whether
this interrupt is generated by its device and if so clear the interrupt
register to disable further generation of interrupts and queue a
DPC to do other I/O work related to interrupt - such as reading
the device memory, starting a DMA transaction, coping it to
the request buffer and completing the request, etc.
Arguments:
Interupt - Handle to WDFINTERRUPT Object for this device.
MessageID - MSI message ID (always 0 in this configuration)
Return Value:
TRUE -- This device generated the interrupt.
FALSE -- This device did not generated this interrupt.
--*/
{
PDEVICE_EXTENSION devExt;
BOOLEAN isRecognized = FALSE;
__int64 i64End;
union {
DMA_INT bits;
ULONG ulong;
} DMAINT;
UNREFERENCED_PARAMETER(MessageID);
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
"--> PCIEInterruptHandler");
// Our ISR Routine will be called event if the test card hasn't trigger any interrupt signal.
// So we comment the debug log here.
// KdPrint(("PCIEEvtInterruptIsr: Begin"));
devExt = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));
//
// Read the Interrupt CSR register (INTCSR)
//
DMAINT.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->INT);
isRecognized = (BOOLEAN)DMAINT.bits.INT_ASSERT;
if(isRecognized)
{
//
// Is write Int?
//
if (DMAINT.bits.INT_WR) {
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
"write Interrupt for DMA Channel");
// Record the TSC now.
_asm rdtsc
_asm mov DWORD PTR i64End, EAX
_asm mov DWORD PTR (i64End+4), EDX
devExt->WriteEndTsc = i64End;
KdPrint(("PCIEEvtInterruptIsr: WriteDMA_Int"));
}
//
// Is DMA read-done?
//
if (DMAINT.bits.INT_RD) {
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
"read Interrupt for DMA Channel");
// Record the TSC now
_asm rdtsc
_asm mov DWORD PTR i64End, EAX
_asm mov DWORD PTR (i64End+4), EDX
devExt->ReadEndTsc = i64End;
KdPrint(("PCIEEvtInterruptIsr: ReadDMA_Int"));
}
// To Clear the Interrupt
WRITE_REGISTER_ULONG((PULONG) &devExt->Regs->INT, DMAINT.ulong);
}
if (isRecognized)
{
//
// A read or a write or both is done. Queue a DPC.
//
// There is no need for this driver to queue a DPC. So we comment it.
//WdfInterruptQueueDpcForIsr( devExt->Interrupt );
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- PCIEInterruptHandler");
KdPrint(("PCIEEvtInterruptIsr: Over"));
return isRecognized;
}
VOID
PCIEEvtInterruptDpc(
IN WDFINTERRUPT Interrupt,
IN WDFDEVICE Device
)
/*++
Routine Description:
DPC callback for ISR. Please note that on a multiprocessor system,
you could have more than one DPCs running simulataneously on
multiple processors. So if you are accesing any global resources
make sure to synchrnonize the accesses with a spinlock.
Arguments:
Interupt - Handle to WDFINTERRUPT Object for this device.
Device - WDFDEVICE object passed to InterruptCreate
Return Value:
--*/
{
NTSTATUS status;
WDFDMATRANSACTION dmaTransaction;
PDEVICE_EXTENSION devExt;
BOOLEAN writeInterrupt = FALSE;
BOOLEAN readInterrupt = FALSE;
__int64 i64End;
UNREFERENCED_PARAMETER(Device);
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc");
KdPrint(("EvtInterruptDpc: Begin"));
devExt = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));
//
// Acquire this device's InterruptSpinLock.
//
WdfInterruptAcquireLock( Interrupt );
if (devExt->DMACSR2.bits.WriteDMADone)
{
devExt->DMACSR2.bits.WriteDMADone = 0;
writeInterrupt = TRUE;
}
if (devExt->DMACSR2.bits.ReadDMADone)
{
devExt->DMACSR2.bits.ReadDMADone = 0;
readInterrupt = TRUE;
}
//
// Release our interrupt spinlock
//
WdfInterruptReleaseLock( Interrupt );
//
// Did a Write DMA complete?
//
if (writeInterrupt) {
_asm rdtsc
_asm mov DWORD PTR i64End, EAX
_asm mov DWORD PTR (i64End + 4), EDX
devExt->WriteEndTsc = i64End;
KdPrint(("PCIEEvtInterruptDpc: writeInterrupt"));
}
//
// Did a Read DMA complete?
//
if (readInterrupt) {
_asm rdtsc
_asm mov DWORD PTR i64End, EAX
_asm mov DWORD PTR (i64End + 4), EDX
devExt->ReadEndTsc = i64End;
KdPrint(("PCIEEvtInterruptDpc: readInterrupt"));
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc");
KdPrint(("EvtInterruptDpc: Over"));
return;
}
NTSTATUS
PCIEEvtInterruptEnable(
IN WDFINTERRUPT Interrupt,
IN WDFDEVICE Device
)
/*++
Routine Description:
Called by the framework at DIRQL immediately after registering the ISR with the kernel
by calling IoConnectInterrupt.
Return Value:
NTSTATUS
--*/
{
KdPrint(("PCIEEvtInterruptEnable"));
return STATUS_SUCCESS;
}
NTSTATUS
PCIEEvtInterruptDisable(
IN WDFINTERRUPT Interrupt,
IN WDFDEVICE Device
)
/*++
Routine Description:
Called by the framework at DIRQL before Deregistering the ISR with the kernel
by calling IoDisconnectInterrupt.
Return Value:
NTSTATUS
--*/
{
KdPrint(("PCIEEvtInterruptDisable"));
return STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -