1. 背景
作为一位标准的 WINDOWN 驱动开发人员最痛苦并快乐着就是如何获取DTDS的硬件资源,并操作GPIO。,
UMDF2 框架的特殊性,并不能直接获取硬件资源和操作GPIO(后期再详解),硬件资源文件DSDT在启动的时候被KERNEL获取和解析,然后通过API的方式UMDF2才能通过KMDF映射并获取资源。
因此,基于此基础上,就有了本文的撰写目的。
2. 概要
2.1 环境约定
运行环境:WIN10/WIN11
开发工具:VS2019
SDK版本:wdksetup.exe
驱动框架:UMDF2
LOG工具: traceview
2.2 参考文档
A.
https://docs.microsoft.com/en-us/windows-hardware/drivers/wdf/finding-and-mapping-hardware-resources
B.
https://docs.microsoft.com/en-us/windows-hardware/drivers/wdf/reading-and-writing-to-device-registers
3. 操作
3.1 DSDT 修改
Device (TpDemo_I2C)
{
Name (_HID, EisaId ("SIL0333") /* PCI Express Bus */) // _HID: Hardware ID
Name (_DDN, "SIL03333_DDN")
Name (_DEP, Package (0x03) // _DEP: Dependencies
{
GPO4,
GPO2,
SPI2
})
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (FBUF, ResourceTemplate ()
{
SpiSerialBusV2 (0x0000, PolarityLow, FourWireMode, 0x08,
ControllerInitiated, 0x000f4240, ClockPolarityLow,
ClockPhaseFirst, "\\_SB.PCI0.SPI2",
0x00, ResourceConsumer, , Exclusive,
)
//PinFunction(Exclusive, PullDefault, 0x5, "\\_SB.GPI22", 0, ResourceConsumer, ) {2, 3}
//PinConfig(Exclusive, 0x01, 10000, "\\_SB.GPI22", 0, ResourceConsumer, ) {2, 3}
/*
Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
{
0x00000048,
}
*/
/*
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPO2", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x004E
}
GpioInt (Level, ActiveHigh, ExclusiveAndWake, PullNone, 0x0000,//GpioInt (Edge, ActiveBoth, ExclusiveAndWake, PullNone, 0x0000,
"\\_SB.GPO4", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0005
} */
GpioIo (Shared, PullNone, 0x0000, 0x0000, IoRestrictionNone,
"\\_SB.GPO2", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0018
}
GpioInt (Edge, ActiveHigh, Shared, PullNone, 0x0000,//GpioInt (Edge, ActiveBoth, Shared, PullNone, 0x0000,
"\\_SB.GPO2", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0018
}
})
// from laptop
/*
CreateWordField (FBUF, 0x3B, RSTP)
CreateWordField (FBUF, 0x5E, INTP)
Store (GNUM (GFPS), RSTP)
Store (GNUM (GFPI), INTP)
*/
Return (FBUF) /* \_SB_.PCI0.SPI1.FP01._CRS.FBUF */
}
}
3.2项目 INF 文件(TpDemo_I2C.inf)
[MyDevice_Install.NT.Wdf]
UmdfService=TpDemo_I2C,TpDemo_I2C_Install
UmdfServiceOrder=TpDemo_I2C
++UmdfDirectHardwareAccess=AllowDirectHardwareAccess
3.3 EvtDevicePrepareHardware
NTSTATUS
SPBDevicePrepareHardware(
_In_
WDFDEVICE Device,
_In_
WDFCMRESLIST ResourcesRaw,
_In_
WDFCMRESLIST ResourcesTranslated
)
{
ULONG resourceCount;
ULONG ix;
BOOLEAN I2ResourceFound = FALSE;
BOOLEAN GPIOResourceFound = FALSE;
PDEVICE_CONTEXT devContext = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
WDF_INTERRUPT_CONFIG interruptConfig;
ULONG interruptIndex = 0;
//(ResourcesRaw);
LOG_MSG_DEBUG("Entry");
/* 1. mapping resource. */
/* 1.1 get the number of resource that the system has assigned to its device ; get it from kmdf ; dsdt --> kmdf --> umdf2 */
resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
/* 1.2 get resource from dsdt file ;dsdt --> kmdf --> umdf2 */
devContext = DeviceGetContext(Device);
devContext->InterruptCount = 0;
for (ix = 0; ix < resourceCount; ix++)
{
//get details about a particular resource from the list.
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
pDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, ix);
if (pDescriptor == NULL)
{
break;
}
switch (pDescriptor->Type)
{
case CmResourceTypeConnection:
{
UCHAR Class = pDescriptor->u.Connection.Class;
UCHAR Type = pDescriptor->u.Connection.Type;
if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL)
{
if (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C)//CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C
{
if (I2ResourceFound == FALSE)
{
// Save the SPB connection ID.
devContext->ConnectionIds[SPB_RESOURCE_INDEX].LowPart =
pDescriptor->u.Connection.IdLowPart;
devContext->ConnectionIds[SPB_RESOURCE_INDEX].HighPart =
pDescriptor->u.Connection.IdHighPart;
LOG_MSG_DEBUG("I2Resource found.\n");
I2ResourceFound = TRUE;
}
}
}
if (Class == CM_RESOURCE_CONNECTION_CLASS_GPIO)
{
// Check for GPIO pin resource.
if (Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)// ±èè?£??òóD?à??gpio??£?
{
if (GPIOResourceFound == FALSE)
{
devContext->ConnectionIds[GPIO_RESOURCE_INDEX].LowPart =
pDescriptor->u.Connection.IdLowPart;
devContext->ConnectionIds[GPIO_RESOURCE_INDEX].HighPart =
pDescriptor->u.Connection.IdHighPart;
LOG_MSG_DEBUG("GPIOResource found.\n");
GPIOResourceFound = TRUE;
}
}
}
}
break;
case CmResourceTypeInterrupt: // ?a??ê????′à′μ?£?
{
devContext->InterruptCount++;
interruptIndex = ix;
// Check for interrupt resource.
//create interrupt object.
}
break;
default:
// Don't care about other resource descriptors.
break;
}//end switch
}
LOG_MSG_DEBUG("Resource values! SPB = %d, GPIO = %d, InterruptCount = %d\n",
I2ResourceFound,
GPIOResourceFound,
devContext->InterruptCount);
if ((devContext->InterruptCount != 1) || (I2ResourceFound != 1) || (GPIOResourceFound != 1))
{
LOG_MSG_DEBUG(" get hw resource failed :%d",status);
return status;
}
else {
status = STATUS_SUCCESS;
}
LOG_MSG_DEBUG("Exit");
return status;
}