Windows on Snapdragon 使用指南(4)

Windows on Snapdragon 使用指南(4)


3 怎么做

以下示例介绍了如何在 Snapdragon 上实现和测试 Windows 的现代待机模式。

3.1 现代(连接)待机模式

在 Snapdragon 上实施和测试将设备从 Windows 的现代待机模式唤醒

使用 GitHub 中的两个 Windows 驱动程序示例和以下说明,您可以在 Snapdragon 平台上实现网络通信并将设备从现代待机模式唤醒。驱动程序示例需要针对 Snapdragon 上的 Windows 进行修改,如下所示。

笔记
这是桌面应用程序的一个特殊用例,需要能够在现代待机期间进行通信,例如在现代待机期间唤醒设备。大多数应用程序不需要此功能,因此无需进行任何修改,桌面应用程序将继续正常工作。Microsoft Store 应用程序可以利用后台任务进行现代待机。您可以在“将应用程序与现代待机集成| Microsoft Learn ”以及 Microsoft 文档中的“什么是现代待机”中的其他背景信息。

安装驱动程序

如果驱动程序在开发过程中未签名,请使用测试证书或测试签名对其进行签名。请务必禁用驱动程序签名强制。

  1. 安装 WSK 驱动程序。
sc create echosrv type=kernel binpath=\echosrv.sy
  1. 从以下位置下载ndisprot630.inf https://github.com/Microsoft/Windows-driver-samples/tree/master/network/ndis/ndisprot/6x/sys/630

  2. 要安装 NDIS 协议驱动程序,请转至“网络连接”,选择一个适配器并打开“属性”。单击安装>协议> 添加>从磁盘安装。然后指向 .inf和驱动程序的位置。选择示例 NDIS 协议驱动程序。
    请添加图片描述
    echosrv — Winsock 内核 (WSK) 驱动程序
    Microsoft 的 Echo 示例内核驱动程序使用 Windows 内核套接字。驱动程序侦听传入的 TCP IPv4/IPv6 请求并回显收到的数据包。GitHub 版本的唯一修改是用于将系统从睡眠状态唤醒的API ( PoSetSystemState )。

  3. https://github.com/microsoft/Windows-driver-samples/tree/master/network/wsk/echosrv获取驱动程序。

  4. 将以下行添加到\network\wsk\echosrv\wsksmple.c。API PoSetSystemState() 应添加到处理接收数据包的函数中。在本例中,这将是WskSampleOpReceive() 。可以在任何位置添加检查是否启用了 AoAC,以检测是否支持现代待机。

PoSetSystemState(ES_DISPLAY_REQUIRED | ES_USER_PRESENT | ES_SYSTEM_REQUIRED );
// Check if Always on Always connected is supported
POWER_PLATFORM_INFORMATION PlatformInfo = {
    
    0};
     NTSTATUS Status = ZwPowerInformation(PlatformInformation,
     NULL,
     0,
     &PlatformInfo,
     sizeof(PlatformInfo));
     if (NT_SUCCESS(Status) && PlatformInfo.AoAc)
     {
    
    ; // "AoAC is enabled!
     }
     else
     {
    
    ; // "AoAC is NOT enabled!
     }
  1. 修改后重新编译驱动。

ndisprot — NDIS 协议驱动程序

对此驱动程序的修改支持 LAN 唤醒 (WOL) 位图模式。其中包括使用OID_PM_ADD_WOL_PATTERN将特定位图模式添加到网络接口卡 (NIC),以及使用类似的 OID 来查询电源管理功能、查询模式并在需要时删除它们。这些更改是必要的,因为当 NIC 进入较低功耗状态 (D2/D3) 时,它会侦听具有特定预配置模式的数据包并丢弃所有其他数据包。

  1. 获取驱动程序 https://github.com/microsoft/Windows-driver-samples/tree/master/network/ndis/ndisprot/6x
  2. 将以下行添加到\network\ndis\ndisprot\6x\sys\ntdisp.c中的 switch (FunctionCode) 语句 :
case IOCTL_NDISPROT_REMOVE_WOL:NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
  if (pOpenContext != NULL)
  {
    
    
   Status = ndisprotSetOidValue(
    pOpenContext,
    pIrp->AssociatedIrp.SystemBuffer,
    pIrpSp->Parameters.DeviceIoControl.InputBufferLength
    );
   BytesReturned = 0;
   NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
  }
  else
  {
    
    
   NtStatus = STATUS_DEVICE_NOT_CONNECTED;
  }
  break;

case IOCTL_NDISPROT_ADD_PAT:
 PBYTE pBegin;
 PBYTE pMask ;
 PBYTE pPattern;
 ULONG MaskSize = 6;
 ULONG PatternSize = 48;
 pBegin = (PBYTE)pIrp->AssociatedIrp.SystemBuffer + FIELD_OFFSET(NDISPROT_SET_OID, Data);
 PNDIS_PM_WOL_PATTERN NdisPattern;
 NdisPattern = (PNDIS_PM_WOL_PATTERN) pBegin;memset(NdisPattern, 0, sizeof(NDIS_PM_WOL_PATTERN));
 NdisPattern->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
 NdisPattern->Header.Revision = NDIS_PM_WOL_PATTERN_REVISION_2 ;
 NdisPattern->Header.Size = NDIS_SIZEOF_NDIS_PM_WOL_PATTERN_REVISION_2 ;
 NdisPattern->Priority = NDIS_PM_WOL_PRIORITY_NORMAL;
 NdisPattern->WoLPacketType = NdisPMWoLPacketBitmapPattern;
 WCHAR str[] = L"QCPat";
 USHORT strLen = 10;
 NdisPattern->FriendlyName.Length = strLen;RtlCopyMemory(NdisPattern->FriendlyName.String, str, strLen);// Put the mask buffer right after the structure// The pattern buffer is located after the mask
 NdisPattern->NextWoLPatternOffset = 0 ;
 NdisPattern->WoLPattern.WoLBitMapPattern.MaskOffset = sizeof(NDIS_PM_WOL_PATTERN);
 NdisPattern->WoLPattern.WoLBitMapPattern.PatternOffset = sizeof(NDIS_PM_WOL_PATTERN) + MaskSize;
 NdisPattern->WoLPattern.WoLBitMapPattern.MaskSize = MaskSize;
 NdisPattern->WoLPattern.WoLBitMapPattern.PatternSize = PatternSize;// Each bit masks 1 byte in the pattern buffer.// Here only the last 6 bytes in the pattern are unmasked
 pMask = pBegin + sizeof(NDIS_PM_WOL_PATTERN);memset(pMask , 0, MaskSize);
 pMask[5] = 0xfc;

 pPattern = pBegin + sizeof(NDIS_PM_WOL_PATTERN) + MaskSize ;// Ethernet Header: 14 Bytes, IP Header: 20 Bytes, UDP Header : 8 Bytes// Combined headers: 42 Bytes, so the payload is starting @ offset 42memset(pPattern, 0, PatternSize);
 pPattern[42] = 0x11;
 pPattern[43] = 0x20;
 pPattern[44] = 0x30;
 pPattern[45] = 0x12;
 pPattern[46] = 0x40;
 pPattern[47] = 0x50;NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);if (pOpenContext != NULL){
    
    
  Status = ndisprotSetOidValue(
   pOpenContext,
   pIrp->AssociatedIrp.SystemBuffer,
   pIrpSp->Parameters.DeviceIoControl.InputBufferLength

启动驱动程序

您可以选择通过修改.inf文件来自动启用驱动程序,也可以使用以下命令:

sc start echosrv
net start ndisprot

添加 WOL 模式

  1. prottest.exe与 NDIS 驱动程序位于同一目录中。在 PowerShell 中,运行prottest -e以枚举设备 ID,如下所示。

  2. 要将 WOL 位图模式添加到 NIC,请运行prottest -a。在下面的示例中,prottest -a将位图模式添加到设备 ID 3。
    请添加图片描述

    • 不带参数的prottest显示帮助。
    • prottest -q查询当前指定的任何模式。
    • prottest -c返回支持的 WOL 数据包类型。

    此时,echosrv 正在端口 40007 上监听 TCP 数据包,并且 WOL 位图模式已设置。当计算机处于睡眠模式时,与 WOL 模式匹配的数据包可以将其唤醒。

  3. 要进行测试,请在目标设备处于睡眠(S0 低功耗空闲连接)模式时,使用 PowerShell 脚本将 WOL 数据包和 TCP 数据包从远程设备发送到目标设备。例如:

Wakeup-Target -IPAddress "fe80::cd1d:936f:fcbf:2fc%12"

停止

  1. 使用以下命令停止驱动程序:
sc stop echosrv
net stop ndisprot
  1. 使用以下命令从 NIC 适配器属性中卸载 ndisprot:
sc delete echosrv

检查与排除故障

现代待机状态— 使用远程设备检查目标设备的现代待机状态。

  1. 确保两个设备可以通信;例如,通过互相 ping 通。
  2. 确保目标设备处于现代(连接)待机状态。它不应处于 S4(休眠)或 S5(关机)模式。
  3. Get-Service echosrv在目标设备上运行以确保 WSK 驱动程序正在运行。
  4. echosrv 驱动程序侦听端口 40007。在目标设备上运行以下命令以确认该端口上有侦听套接字。
Get-NetTCPConnection -LocalPort 40007

请添加图片描述
prottest.exe — 如果 prottest.exe 不起作用,您可能需要安装 Visual C++。

现代待机支持— 运行以下命令以确认支持并启用现代(连接)待机(S0 低功耗空闲连接):

Powercfg /a

例如:

c:\>powercfg /a
The following sleep state are available on this system:
    Standby (S0 Low Power Idle) Network Connected
    Fast Startup

电源状态— 运行以下命令来研究系统电源状态:

Powercfg /sleepstudy

例如:

c:\>powercfg /sleepstudy
Sleep Study report saved to file path c:\sleepstudy-report.html.

如下面的摘录所示,报告显示了每种模式(活动、待机、休眠、睡眠等)所花费的时间以及进入和退出每种状态的原因。

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_38498942/article/details/132837035
今日推荐