Lecture et écriture dans les registres d’appareils
Une fois qu’un pilote a mappé des registres comme décrit dans Recherche et mappage des ressources matérielles, un pilote KMDF utilise les routines de bibliothèque HAL pour lire et écrire dans les registres, tandis qu’un pilote UMDF (version 2.0 ou ultérieure) utilise généralement les fonctions d’accès au registre/port WDF.
Si un pilote UMDF doit accéder directement aux registres mappés en mémoire, il peut définir la directive INF UmdfRegisterAccessMode surRegisterAccessUsingUserModeMapping , puis appeler WdfDeviceGetHardwareRegisterMappedAddress pour récupérer une adresse mappée en mode utilisateur. Étant donné que l’infrastructure ne valide pas les accès en lecture et en écriture effectués de cette manière, cette technique n’est pas recommandée pour l’accès d’inscription. Pour obtenir la liste complète des directives INF UMDF, consultez Spécification de directives WDF dans les fichiers INF.
L’exemple suivant inclut du code qui peut être compilé à l’aide de KMDF (1.13 ou version ultérieure) ou UMDF (2.0 ou version ultérieure). L’exemple montre comment un pilote utilise sa fonction de rappel EvtDevicePrepareHardware pour examiner ses ressources de registre mappées en mémoire et les mapper dans l’espace d’adressage en mode utilisateur. L’exemple montre ensuite comment accéder aux emplacements de mémoire.
Avant d’accéder aux registres d’appareils et aux ports, un pilote UMDF doit définir la directive UmdfDirectHardwareAccess sur AllowDirectHardwareAccess dans le fichier INF du pilote.
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;
}