Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве показано, как написать функциональный драйвер NFC с помощью драйвера NFC Class Extension (NFC CX).
Примечание
Драйвер, использующий драйвер расширения класса в своей реализации, называется клиентским драйвером. То есть клиент драйвера расширения класса.
Предварительные требования
- Встроенное ПО контроллера NFC должно реализовывать протокол NFC-интерфейса контроллера (NCI) форума NFC .
- Visual Studio 2017 (или более поздней версии).
- Windows SDK.
- Комплект драйверов Windows (WDK).
Обязанности водителя клиента
Драйвер NFC CX отвечает за обработку запросов ввода-вывода, отправленных драйверу, и создание соответствующих пакетов команд 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.inf>.
В INF-файле удалите пользовательский класс устройства, выполнив следующие действия.
Удалите следующие два раздела:
[ClassInstall32] AddReg=SampleClass_RegistryAdd [SampleClass_RegistryAdd] HKR,,,,%ClassName% HKR,,Icon,,"-10"
[Strings]
В разделе удалите следующую строку.ClassName="Samples" ; TODO: edit ClassName
В INF-файле задайте для класса устройства драйвера значение Proximity:
- Измените значение
Class
наProximity
- Измените значение
ClassGuid
на{5630831C-06C9-4856-B327-F5D32586E060}
- Это GUID класса устройства Proximity.
[Version] ... Class=Proximity ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} ; Proximity class GUID ...
- Измените значение
В INF-файле добавьте ссылку на расширение класса NFC. Это гарантирует, что Windows Driver Framework (WDF) загружает драйвер NFC CX при загрузке драйвера клиента.
- Найдите раздел
<project-name>_Install
. - Добавьте
UmdfExtensions=NfcCx0102
.
[<project-name>_Install] ... UmdfExtensions=NfcCx0102
- Найдите раздел
В параметрах сборки драйвера установите ссылку на расширение класса NFC. Это гарантирует, что API NFC CX будет доступен во время компиляции кода.
- В обозревателе решений щелкните правой кнопкой мыши проект и выберите Свойства. В разделе Свойства конфигурации в разделе Параметры драйвера выберите NFC.
- Убедитесь, что для параметра Конфигурация задано значение
All Configurations
. - Убедитесь, что для параметра Platform задано значение
All Platforms
. - Задайте для link to NFC Class Extension значение
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
вызова. Этот обратный вызов получает пакеты NCI от драйвера NFC CX, который драйвер клиента должен перенаправить контроллеру 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
вызовов питания PnP иD0Exit
. Однако это может отличаться в зависимости от того, как драйвер клиента обрабатывает управление питанием.// 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 CX при наличии пакета NCI для отправки на контроллер NFC.
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 содержит пакет NCI, который должен быть отправлен в NFC CX. Обычно это делается в обратном вызове события оборудования.Пример:
- Обратный вызов события прерывания GPIO . (I2C и SPI)
- Обратный вызов непрерывного чтения USB .
Ведение журнала
Рассмотрите возможность добавления ведения журнала в драйвер клиента, чтобы упростить отладку. Хорошими вариантами являются трассировка etw и трассировка WPP .