NFC CX 快速入门指南
本指南演示如何使用 NFC 类扩展 (NFC CX) 驱动程序编写 NFC 功能驱动程序。
注意
在其实现中使用类扩展驱动程序的驱动程序称为“客户端驱动程序”。 也就是说,类扩展驱动程序的客户端。
先决条件
- NFC 控制器的固件必须实现 NFC 论坛的 NFC 控制器接口 (NCI) 协议。
- Visual Studio 2017 (或更高版本) 。
- Windows SDK。
- Windows 驱动程序工具包 (WDK) 。
客户端驱动程序职责
NFC CX 驱动程序负责处理发送到驱动程序的 I/O 请求并创建相关的 NCI 命令数据包。 客户端驱动程序负责将这些 NCI 数据包发送到 NFC 控制器,并将 NCI 响应数据包发回 NFC CX 驱动程序。
由客户端驱动程序决定如何将 NCI 数据包发送到 NFC 控制器。 此过程因使用的硬件总线类型而异。 NFC 控制器使用的常见总线包括 I2C、SPI 和 USB。
完整的项目代码
GitHub 上提供了此示例代码的完整版本: NFC CX 客户端驱动程序示例。
项目设置
在 Visual Studio 中,创建新的“用户模式驱动程序,空 (UMDF V2) ”项目。
在 “文件” 菜单上,指向 “新建”,然后选择 “项目”。 在 Visual C++ 节点的 “Windows 驱动程序”下,选择“ WDF”,然后选择“ 用户模式驱动程序”、“空 (UMDF V2)
打开 INF 文件。
在 解决方案资源管理器,在“驱动程序文件”文件夹中的<“project-name>”节点下,双击“<project-name.inf>”。
在 INF 文件中,使用以下步骤删除自定义设备类:
删除以下两个部分:
[ClassInstall32] AddReg=SampleClass_RegistryAdd [SampleClass_RegistryAdd] HKR,,,,%ClassName% HKR,,Icon,,"-10"
在
[Strings]
部分下,删除以下行。ClassName="Samples" ; TODO: edit ClassName
在 INF 文件中,将驱动程序的设备类设置为 邻近感应:
- 将 的值
Class
更改为Proximity
- 将 的值
ClassGuid
更改为{5630831C-06C9-4856-B327-F5D32586E060}
- 这是邻近感应设备类的 GUID。
[Version] ... Class=Proximity ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} ; Proximity class GUID ...
- 将 的值
在 INF 文件中,添加对 NFC 类扩展的引用。 这样做可确保 Windows 驱动程序框架 (WDF) 客户端驱动程序加载时加载 NFC CX 驱动程序。
- 找到
<project-name>_Install
节。 - 添加
UmdfExtensions=NfcCx0102
。
[<project-name>_Install] ... UmdfExtensions=NfcCx0102
- 找到
在驱动程序生成设置中,链接到 NFC 类扩展。 这样做可确保 NFC CX API 在代码编译期间可用。
- 在“解决方案资源管理器” 中,右键单击项目,然后选择“属性” 。 在“配置属性”中的“驱动程序设置”下,选择“NFC”。
- 确保 “配置” 设置为
All Configurations
。 - 确保 将“平台 ”设置为
All Platforms
。 - 将 “NFC 类扩展的链接 ”设置为
Yes
。
将名为
Driver.cpp
的文件添加到项目。DriverEntry
在 中创建Driver.cpp
例程。 这是驱动程序的入口点。 它的主要用途是初始化 WDF 并注册EvtDriverDeviceAdd
回调函数。#include <windows.h> #include <wdf.h> #include "Device.h" // created in Step 9 // The entry point for the driver. extern "C" NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; // Specify `DeviceContext::AddDevice` as the // `EvtDriverDeviceAdd` function for the driver. WDF_DRIVER_CONFIG driverConfig; WDF_DRIVER_CONFIG_INIT(&driverConfig, DeviceContext::AddDevice); // Initialize WDF. status = WdfDriverCreate( DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &driverConfig, WDF_NO_HANDLE); if (!NT_SUCCESS(status)) { return status; } return STATUS_SUCCESS; }
将两个名为
Device.cpp
和Device.h
的文件添加到项目中。在
Device.h
中,DeviceContext
定义 类。#pragma once #include <windows.h> #include <wdf.h> #include <NfcCx.h> // The class that will store the driver's custom state for // a device instance. class DeviceContext { public: // Implementation of `EvtDriverDeviceAdd`. static NTSTATUS AddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit); private: // Implementation of `EvtDevicePrepareHardware`. static NTSTATUS PrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated); // Implementation of `EvtDeviceReleaseHardware`. static NTSTATUS ReleaseHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesTranslated); // Implementation of `EvtDeviceD0Entry`. static NTSTATUS D0Entry( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState); // Implementation of `EvtDeviceD0Exit`. static NTSTATUS D0Exit( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE TargetState); // Implementation of `EvtNfcCxWriteNciPacket`. static void WriteNciPacket( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request); }; // Define the `DeviceGetContext` function. WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DeviceContext, DeviceGetContext);
在
Device.cpp
中,开始DeviceContext::AddDevice
函数的定义。#include "Device.h" NTSTATUS DeviceContext::AddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) { NTSTATUS status;
设置 NFC CX 设备配置。 设备配置包括提供
EvtNfcCxWriteNciPacket
回调函数。 此回调从 NFC CX 驱动程序接收 NCI 数据包,客户端驱动程序应将其转发到 NFC 控制器。// Create the NfcCx config. NFC_CX_CLIENT_CONFIG nfcCxConfig; NFC_CX_CLIENT_CONFIG_INIT(&nfcCxConfig, NFC_CX_TRANSPORT_CUSTOM); nfcCxConfig.EvtNfcCxWriteNciPacket = WriteNciPacket; nfcCxConfig.DriverFlags = NFC_CX_DRIVER_ENABLE_EEPROM_WRITE_PROTECTION; // Set the NfcCx config. status = NfcCxDeviceInitConfig(DeviceInit, &nfcCxConfig); if (!NT_SUCCESS(status)) { return status; }
注册客户端驱动程序所需的 PnP 电源回调 。
典型的客户端驱动程序可能需要
EvtDevicePrepareHardware
、EvtDeviceReleaseHardware
、EvtDeviceD0Entry
和EvtDeviceD0Exit
函数。 要求可能因客户端驱动程序处理电源管理的方式而异。// Create the PnP power callbacks configuration. WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDevicePrepareHardware = PrepareHardware; pnpCallbacks.EvtDeviceReleaseHardware = ReleaseHardware; pnpCallbacks.EvtDeviceD0Entry = D0Entry; pnpCallbacks.EvtDeviceD0Exit = D0Exit; // Set the PnP power callbacks. WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks);
WdfDeviceCreate
调用 函数以创建WDFDEVICE
对象。// Create WDF object attributes for the WDFDEVICE object. WDF_OBJECT_ATTRIBUTES deviceAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DeviceContext); // Create the device. WDFDEVICE device; status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (!NT_SUCCESS(status)) { return status; }
调用
NfcCxDeviceInitialize
函数。应在创建 对象后
WDFDEVICE
调用此函数,以允许 NFC CX 驱动程序完成设备实例的初始化。// Let NFC CX finish initializing the device instance. status = NfcCxDeviceInitialize(device); if (!NT_SUCCESS(status)) { return status; }
调用
NfcCxSetRfDiscoveryConfig
以指定 NFC 控制器支持的 NFC 技术和协议。// Create the RF config. (Enable everything.) NFC_CX_RF_DISCOVERY_CONFIG discoveryConfig; NFC_CX_RF_DISCOVERY_CONFIG_INIT(&discoveryConfig); discoveryConfig.PollConfig = NFC_CX_POLL_NFC_A | NFC_CX_POLL_NFC_B | NFC_CX_POLL_NFC_F_212 | NFC_CX_POLL_NFC_F_424 | NFC_CX_POLL_NFC_15693 | NFC_CX_POLL_NFC_ACTIVE | NFC_CX_POLL_NFC_A_KOVIO; discoveryConfig.NfcIPMode = NFC_CX_NFCIP_NFC_A | NFC_CX_NFCIP_NFC_F_212 | NFC_CX_NFCIP_NFC_F_424 | NFC_CX_NFCIP_NFC_ACTIVE | NFC_CX_NFCIP_NFC_ACTIVE_A | NFC_CX_NFCIP_NFC_ACTIVE_F_212 | NFC_CX_NFCIP_NFC_ACTIVE_F_424; discoveryConfig.NfcIPTgtMode = NFC_CX_NFCIP_TGT_NFC_A | NFC_CX_NFCIP_TGT_NFC_F | NFC_CX_NFCIP_TGT_NFC_ACTIVE_A | NFC_CX_NFCIP_TGT_NFC_ACTIVE_F; discoveryConfig.NfcCEMode = NFC_CX_CE_NFC_A | NFC_CX_CE_NFC_B | NFC_CX_CE_NFC_F; // Set the RF config. status = NfcCxSetRfDiscoveryConfig(device, &discoveryConfig); if (!NT_SUCCESS(status)) { return status; }
DeviceContext::AddDevice
结束函数。return STATUS_SUCCESS; }
PrepareHardware
实现 和ReleaseHardware
回调函数。这两个函数用于初始化和取消初始化分配给 NFC 控制器设备实例的硬件资源。 其实现取决于设备连接到 (的总线类型,例如 I2C、SPI 和 USB) 。
NTSTATUS DeviceContext::PrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated) { // FIX ME: Initialize hardware resources. return STATUS_SUCCESS; } NTSTATUS DeviceContext::ReleaseHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesTranslated) { // FIX ME: Uninitialize hardware resources. return STATUS_SUCCESS; }
NfcCxHardwareEvent
使用HostActionStart
和HostActionStop
调用 函数,以在适当的时间启动和停止 NCI 状态机。某些驱动程序在
D0Entry
和D0Exit
PnP 电源回调期间执行此操作。 不过,这可能因客户端驱动程序处理电源管理的方式而异。// Device exiting low power state (or is booting up). NTSTATUS DeviceContext::D0Entry( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState) { (void)PreviousState; NTSTATUS status; // Invoke the HostActionStart event, so that the NFC CX initializes // the NFC Controller. NFC_CX_HARDWARE_EVENT eventArgs = {}; eventArgs.HostAction = HostActionStart; status = NfcCxHardwareEvent(Device, &eventArgs); if (!NT_SUCCESS(status)) { return status; } return STATUS_SUCCESS; } // Device entering low power state. NTSTATUS DeviceContext::D0Exit( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE TargetState) { (void)TargetState; NTSTATUS status; // Trigger the HostActionStop event, so that the NFC CX // uninitializes the NFC Controller. NFC_CX_HARDWARE_EVENT eventArgs = {}; eventArgs.HostAction = HostActionStop; status = NfcCxHardwareEvent(Device, &eventArgs); if (!NT_SUCCESS(status)) { return status; } return STATUS_SUCCESS; }
实现
WriteNciPacket
函数。当有要发送到 NFC 控制器的 NCI 数据包时,NFC CX 会调用此回调。
void DeviceContext::WriteNciPacket( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request) { NTSTATUS status; // Get the NCI packet as a raw byte buffer. void* nciPacket; size_t nciPacketLength; status = WdfRequestRetrieveInputBuffer(Request, 0, &nciPacket, &nciPacketLength); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } // FIX ME: Use the NCI packet in some way. // FIX ME: Call `WdfRequestComplete` on `Request` with failure // or success `NTSTATUS` code. };
NfcCxNciReadNotification
当 NFC 控制器具有应发送到 NFC CX 的 NCI 数据包时,调用 函数。 这通常在硬件事件回调中完成。例如:
日志记录
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈