Чтение и запись в регистры устройств
После сопоставления регистров драйвера, как описано в разделе Поиск и сопоставление аппаратных ресурсов, драйвер KMDF использует подпрограммы библиотеки HAL для чтения и записи в регистры, а драйвер UMDF (версии 2.0 или более поздней) обычно использует функции регистрации/доступа к портам WDF.
Если драйверу UMDF требуется прямой доступ к регистрам, сопоставленным с памятью, он может задать директиве INF UmdfRegisterAccessAccessModeзначение RegisterAccessUsingUserModeMapping , а затем вызвать WdfDeviceGetHardwareRegisterMappedAddress , чтобы получить сопоставленный адрес в пользовательском режиме. Так как платформа не проверяет доступы на чтение и запись, выполняемые таким образом, этот метод не рекомендуется для регистрации доступа. Полный список директив INF UMDF см. в разделе Указание директив WDF в INF-файлах.
Следующий пример содержит код, который можно скомпилировать с помощью KMDF (1.13 или более поздней версии) или UMDF (2.0 или более поздней версии). В примере показано, как драйвер использует функцию обратного вызова EvtDevicePrepareHardware для проверки ресурсов регистра, сопоставленных в памяти, и их сопоставления с адресным пространством в пользовательском режиме. Затем в примере показано, как получить доступ к расположениям памяти.
Перед доступом к регистрам и портам устройств драйвер UMDF должен задать директиве UmdfDirectHardwareAccessзначение AllowDirectHardwareAccess в INF-файле драйвера.
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);
MyKdPrint(("MyEvtDevicePrepareHardware Device 0x%p ResRaw 0x%p ResTrans "
"0x%p Count %d\n", Device, ResourcesRaw, ResourcesTranslated,
WdfCmResourceListGetCount(ResourcesTranslated)));
#ifndef _KERNEL_MODE
WDF_DEVICE_IO_TYPE stackReadWriteIotype = WdfDeviceIoUndefined;
WDF_DEVICE_IO_TYPE stackIoctlIotype = WdfDeviceIoUndefined;
WdfDeviceGetDeviceStackIoType(Device,
&stackReadWriteIotype,
&stackIoctlIotype);
MyKdPrint(("Device 0x%p stackReadWriteIoType %S stackIoctlIoType %S\n",
Device,
GetIoTypeName(stackReadWriteIotype),
GetIoTypeName(stackIoctlIotype)
));
#endif
deviceContext = ToasterFdoGetData(Device);
//
// Scan the list and identify our resource
//
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;
}