读取设备注册表和写入到设备注册表
驱动程序映射寄存器后,如 查找和映射硬件资源所述,KMDF 驱动程序使用 HAL 库例程 读取和写入寄存器,而 版本 2.0 或更高版本的 UMDF 驱动程序通常使用 WDF 寄存器/端口访问函数。
如果 UMDF 驱动程序需要直接访问内存映射的寄存器,它可以将 INF 指令 UmdfRegisterAccessMode 设置为 RegisterAccessUsingUserModeMapping ,然后调用 WdfDeviceGetHardwareRegisterMappedAddress 来检索用户模式映射地址。 由于框架不会验证以这种方式执行的读取和写入访问,因此不建议将此方法用于注册访问。 有关 UMDF INF 指令的完整列表,请参阅 在 INF 文件中指定 WDF 指令。
以下示例包括可以使用 KMDF (1.13 或更高版本) 或 UMDF (2.0 或更高版本) 编译的代码。 该示例演示驱动程序如何使用其 EvtDevicePrepareHardware 回调函数检查其内存映射的寄存器资源并将其映射到用户模式地址空间。 然后,该示例演示如何访问内存位置。
在访问设备寄存器和端口之前,UMDF 驱动程序必须在驱动程序的 INF 文件中将 UmdfDirectHardwareAccess 指令设置为 AllowDirectHardwareAccess 。
// 下面的代码节选自Toaster
NTSTATUS
MyDevicePrepareHardware (
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourcesRaw,
IN WDFCMRESLIST ResourcesTranslated
)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR descTranslated = NULL;
PHYSICAL_ADDRESS regBasePA = {0};
ULONG regLength = 0;
BOOLEAN found = FALSE;
ULONG i;
PFDO_DATA deviceContext;
NTSTATUS status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(ResourcesRaw);
#ifndef _KERNEL_MODE
WDF_DEVICE_IO_TYPE stackReadWriteIotype = WdfDeviceIoUndefined;
WDF_DEVICE_IO_TYPE stackIoctlIotype = WdfDeviceIoUndefined;
// 获取资源标志
WdfDeviceGetDeviceStackIoType(Device,
&stackReadWriteIotype,
&stackIoctlIotype);
#endif
deviceContext = ToasterFdoGetData(Device);
//
// 扫描资源标志来处理硬件资源列表
//
for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
desc = WdfCmResourceListGetDescriptor(Resources, i);
descTranslated = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);
switch (desc->Type)
{
case CmResourceTypeMemory:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeMemory resources \n"));
//
// see if this is the memory resource we're looking for
//
if (desc->u.Memory.Length == 0x200) {
regBasePA = desc->u.Memory.Start;
regLength = desc->u.Memory.Length;
found = TRUE;
}
break;
case CmResourceTypePort:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypePort"
" resource\n"));
switch(descTranslated->Type) {
case CmResourceTypePort:
deviceContext->PortWasMapped = FALSE;
deviceContext->PortBase =
ULongToPtr(descTranslated->u.Port.Start.LowPart);
deviceContext->PortCount = descTranslated ->u.Port.Length;
MyKdPrint(("Resource Translated Port: (%x) Length: (%d)\n",
descTranslated->u.Port.Start.LowPart,
descTranslated->u.Port.Length));
break;
case CmResourceTypeMemory:
//
// Map the memory
//
#if IS_UMDF_DRIVER
status = WdfDeviceMapIoSpace(
Device,
descTranslated->u.Memory.Start,
descTranslated->u.Memory.Length,
MmNonCached,
&deviceContext->PortBase
);
if (!NT_SUCCESS(status)) {
WdfVerifierDbgBreakPoint();
}
#else
deviceContext->PortBase = (PVOID)
MmMapIoSpace(
descTranslated->u.Memory.Start,
descTranslated->u.Memory.Length,
MmNonCached
);
UNREFERENCED_PARAMETER(status);
#endif
deviceContext->PortCount = descTranslated->u.Memory.Length;
deviceContext->PortWasMapped = TRUE;
MyKdPrint(("Resource Translated Memory: (%x) Length: (%d)\n",
descTranslated->u.Memory.Start.LowPart,
descTranslated->u.Memory.Length));
break;
default:
MyKdPrint(("Unhandled resource_type (0x%x)\n",
descTranslated->Type));
}
break;
case CmResourceTypeInterrupt:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeInterrupt"
"resource\n"));
break;
case CmResourceTypeConnection:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeConnection"
"resource\n"));
break;
default:
MyKdPrint(("EvtPrepareHardware: found resources of type %d"
"(CM_RESOURCE_TYPE)\n", desc->Type));
break;
}
}
//
// Next, the driver uses register/port access macros to access the port.
//
if ((PUCHAR)&deviceContext->PortBase != NULL) {
UCHAR data;
#ifndef _KERNEL_MODE
data = WDF_READ_PORT_UCHAR(Device, (PUCHAR)deviceContext->PortBase);
#else
data = READ_PORT_UCHAR((PUCHAR)deviceContext->PortBase);
#endif
MyKdPrint(("Read value %d from port address 0x%p\n", data,
deviceContext->PortBase));
}
if (i == 0) {
MyKdPrint(("EvtPrepareHardware: no cm resources found \n"));
}
return STATUS_SUCCESS;
}
NTSTATUS
MyDeviceReleaseHardware (
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourcesTranslated
)
{
PFDO_DATA deviceContext;
UNREFERENCED_PARAMETER(ResourcesTranslated);
MyKdPrint(("CovEvtDeviceReleaseHardware Device 0x%p ResTrans 0x%p\n",
Device, ResourcesTranslated));
deviceContext = ToasterFdoGetData(Device);
if (deviceContext->PortWasMapped) {
#if IS_UMDF_DRIVER
WdfDeviceUnmapIoSpace(Device,
deviceContext->PortBase,
deviceContext->PortCount);
#else
MmUnmapIoSpace(deviceContext->PortBase,
deviceContext->PortCount);
#endif
}
return STATUS_SUCCESS;
}