📄 init.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:
Init.c
Abstract:
Contains most of initialization functions
Environment:
Kernel mode
--*/
#include "precomp.h"
#include "Init.tmh"
#include <wdm.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, PCIEInitializeDeviceExtension)
#pragma alloc_text (PAGE, PCIEPrepareHardware)
#pragma alloc_text (PAGE, PCIEInitializeDMA)
#pragma alloc_text (PAGE, PCIEInitWrite)
#pragma alloc_text (PAGE, PCIEInitRead)
#endif
void PCIEWait(int ms);
VOID PCIEIOCtrlCode(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
);
NTSTATUS
PCIEInitializeDeviceExtension(
IN PDEVICE_EXTENSION DevExt
)
/*++
Routine Description:
This routine is called by EvtDeviceAdd. Here the device context is
initialized and all the software resources required by the device is
allocated.
Arguments:
DevExt Pointer to the Device Extension
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
ULONG dteCount;
WDF_IO_QUEUE_CONFIG queueConfig;
PAGED_CODE();
DevExt->MaximumTransferLength = PCIE_MAXIMUM_TRANSFER_LENGTH;
DevExt->BufferSystemVirtualAddress = NULL;
DevExt->BufferUserVirtualAddress = NULL;
DevExt->BufferMdl = NULL;
DevExt->Buffer2SystemVirtualAddress = NULL;
DevExt->Buffer2UserVirtualAddress = NULL;
DevExt->Buffer2Mdl = NULL;
//
// Setup a queue to handle only IRP_MJ_WRITE requests in Sequential
// dispatch mode. This mode ensures there is only one write request
// outstanding in the driver at any time. Framework will present the next
// request only if the current request is completed.
// Since we have configured the queue to dispatch all the specific requests
// we care about, we don't need a default queue. A default queue is
// used to receive requests that are not preconfigured to goto
// a specific queue.
//
WDF_IO_QUEUE_CONFIG_INIT ( &queueConfig,
WdfIoQueueDispatchSequential);
queueConfig.EvtIoDeviceControl = PCIEIOCtrlCode;
status = WdfIoQueueCreate( DevExt->Device,
&queueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&DevExt->IOCtrlQueue );
if(!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"WdfIoQueueCreate failed: %!STATUS!", status);
return status;
}
//
// Set the Write Queue forwarding for IRP_MJ_WRITE requests.
//
status = WdfDeviceConfigureRequestDispatching( DevExt->Device,
DevExt->IOCtrlQueue,
WdfRequestTypeDeviceControl);
if(!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"DeviceConfigureRequestDispatching failed: %!STATUS!", status);
return status;
}
//
// Create a WDFINTERRUPT object.
//
status = PCIEInterruptCreate(DevExt);
if (!NT_SUCCESS(status)) {
return status;
}
return status;
}
NTSTATUS
PCIEPrepareHardware(
IN PDEVICE_EXTENSION DevExt,
IN WDFCMRESLIST ResourcesTranslated
)
/*++
Routine Description:
Gets the HW resources assigned by the bus driver from the start-irp
and maps it to system address space.
Arguments:
DevExt Pointer to our DEVICE_EXTENSION
Return Value:
None
--*/
{
ULONG i;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN foundAddress = FALSE;
PHYSICAL_ADDRESS AddressBasePA = {0};
ULONG AddressLength = 0;
PHYSICAL_ADDRESS physicalAddress = {0, 0};
ULONG j;
WDF_DMA_ENABLER_CONFIG dmaConfig;
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
PAGED_CODE();
DevExt->BufferPhysicalAddress = NULL;
DevExt->BufferLogicalAddress = NULL;
DevExt->BufferSize = 0;
DevExt->Buffer2PhysicalAddress = NULL;
DevExt->Buffer2LogicalAddress = NULL;
DevExt->Buffer2Size = 0;
//
// Parse the resource list and save the resource information.
//
for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );
if(!desc) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"WdfResourceCmGetDescriptor failed");
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
switch (desc->Type) {
case CmResourceTypeMemory:
if (!foundAddress )
{
AddressBasePA = desc->u.Memory.Start;
AddressLength = desc->u.Memory.Length;
foundAddress = TRUE;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" BAR0 TRACED");
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" - Memory Resource [%I64X-%I64X] BAR0",
desc->u.Memory.Start.QuadPart,
desc->u.Memory.Start.QuadPart + desc->u.Memory.Length );
break;
default:
//
// Ignore all other descriptors
//
break;
}
}
if (!foundAddress)
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"PCIEMapResources: Missing resources");
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// Map in the Registers Memory resource: BAR0
//
// ????
AddressLength = sizeof(ULONG) * 64;
DevExt->RegsPhyBase = (PUCHAR)AddressBasePA.LowPart;
DevExt->RegsBase = (PUCHAR) MmMapIoSpace( AddressBasePA,
AddressLength,
MmNonCached );
DevExt->RegsLength = AddressLength;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" - Registers %p, length %d",
DevExt->RegsBase, DevExt->RegsLength );
if (!DevExt->RegsBase) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
" - Unable to map BAR1 memory %08I64X, length %d",
AddressBasePA.QuadPart, AddressLength);
return STATUS_INSUFFICIENT_RESOURCES;
}
DevExt->Regs = (PPCIE_REGS)DevExt->RegsBase;
// Allocate The Buffer for DMA
// DWORD X 0x20 X MAXCount(1024) = 4 x 32 x 1024 = 128 K
DevExt->BufferSize = PCIE_BUFFER_SIZE; // 16 M
DevExt->Buffer2Size = PCIE_BUFFER_SIZE; // 16 M
physicalAddress.LowPart = 0x80000000;
physicalAddress.HighPart = 0;
DevExt->BufferLogicalAddress = MmAllocateContiguousMemory(DevExt->BufferSize, physicalAddress);
DevExt->Buffer2LogicalAddress = MmAllocateContiguousMemory(DevExt->Buffer2Size, physicalAddress);
if (DevExt->BufferLogicalAddress)
{
physicalAddress = MmGetPhysicalAddress((PVOID)DevExt->BufferLogicalAddress);
DevExt->BufferPhysicalAddress = (PUCHAR)physicalAddress.LowPart;
KdPrint(("PCIE: Alloc Physical Buffer OK!"));
}
else
{
KdPrint(("PCIE: Alloc Physical Buffer FAILED!"));
}
if (DevExt->Buffer2LogicalAddress)
{
physicalAddress = MmGetPhysicalAddress((PVOID)DevExt->Buffer2LogicalAddress);
DevExt->Buffer2PhysicalAddress = (PUCHAR)physicalAddress.LowPart;
KdPrint(("PCIE: Alloc Physical Buffer 2 OK!"));
}
else
{
KdPrint(("PCIE: Alloc Physical Buffer 2 FAILED!"));
}
return status;
}
VOID
PCIEShutdown(
IN PDEVICE_EXTENSION DevExt
)
/*++
Routine Description:
Reset the device to put the device in a known initial state.
This is called from D0Exit when the device is torn down or
when the system is shutdown. Note that Wdf has already
called out EvtDisable callback to disable the interrupt.
Arguments:
DevExt - Pointer to our adapter
Return Value:
None
--*/
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "---> PCIEShutdown");
//
// WdfInterrupt is already disabled so issue a full reset
//
if (DevExt->Regs) {
PCIEHardwareReset(DevExt);
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<--- PCIEShutdown");
}
VOID
PCIEHardwareReset(
IN PDEVICE_EXTENSION DevExt
)
/*++
Routine Description:
Called by D0Exit when the device is being disabled or when the system is shutdown to
put the device in a known initial state.
Arguments:
DevExt Pointer to Device Extension
Return Value:
--*/
{
LARGE_INTEGER delay;
union {
DMA_CSR1 bits;
ULONG ulong;
} DMACSR1;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PCIEHardwareReset");
//
// Drive the device into soft reset.
//
DMACSR1.ulong = READ_REGISTER_ULONG( (PULONG) &DevExt->Regs->DCSR1 );
DMACSR1.bits.InitiatorReset = 1;
WRITE_REGISTER_ULONG((PULONG) &DevExt->Regs->DCSR1, DMACSR1.ulong );
//
// Wait 100 msec.
//
delay.QuadPart = WDF_REL_TIMEOUT_IN_MS(100);
KeDelayExecutionThread( KernelMode, TRUE, &delay );
//
// Finally pull the device out of reset.
//
DMACSR1.bits.InitiatorReset = 0;
WRITE_REGISTER_ULONG((PULONG) &DevExt->Regs->DCSR1, DMACSR1.ulong );
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PCIEIssueFullReset");
}
void PCIEWait(int ms)
{
LARGE_INTEGER delay;
delay.QuadPart = WDF_REL_TIMEOUT_IN_MS(ms);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -