通过
- 项目
本指南演示如何使用 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=ProximityClassGuid={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 数据包时,调用 函数。 这通常在硬件事件回调中完成。
例如:
- GPIO 中断事件回调。 (I2C 和 SPI)
- USB 连续读卡器回调。
日志记录
请考虑将日志记录添加到客户端驱动程序,使其更易于调试。 ETW 跟踪和 WPP 跟踪都是不错的选择。
反馈
此页面是否有帮助?
提供产品反馈|