Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este guia demonstra como escrever um driver funcional NFC usando o driver NFC CX (Extensão de Classe NFC).
Note
Um driver que usa um driver de extensão de classe em sua implementação é conhecido como um "driver cliente". Ou seja, um cliente do driver de extensão de classe.
Prerequisites
- O firmware do controlador NFC deve implementar o protocolo NCI (Nfc Controller Interface) do Fórum NFC.
- Visual Studio 2017 (ou posterior).
- O SDK do Windows.
- O Kit de Driver do Windows (WDK).
Responsabilidades do driver do cliente
O driver CX NFC é responsável por lidar com solicitações de E/S enviadas ao driver e criar os pacotes de comando NCI relevantes. O driver cliente é responsável por enviar esses pacotes de NCI para o Controlador NFC e enviar de volta os pacotes de resposta NCI para o driver CX NFC.
Cabe ao driver cliente determinar como enviar os pacotes de NCI para o controlador NFC. Esse processo varia dependendo do tipo de barramento de hardware usado. Os barramentos comuns usados pelos controladores NFC incluem I2C, SPI e USB.
Código completo do projeto
Uma versão completa deste código de exemplo está disponível em GitHub: exemplo de driver de cliente NFC CX.
Configuração do projeto
No Visual Studio, crie um novo projeto "Driver do Modo de Usuário, Vazio (UMDF V2)".
No menu Arquivo , aponte para Novoe selecione Projeto. No nó Visual C++, em Drivers do Windows, selecione WDF e, em seguida, selecione Driver do Modo de Usuário, Vazio (UMDF V2)
Abra o arquivo INF.
Em Gerenciador de Soluções, no nó >project-name<, na pasta Arquivos de Driver, clique duas vezes em <project-name>.inf.
No arquivo INF, remova a classe de dispositivo personalizada usando as seguintes etapas:
Remova as duas seções a seguir:
[ClassInstall32] AddReg=SampleClass_RegistryAdd [SampleClass_RegistryAdd] HKR,,,,%ClassName% HKR,,Icon,,"-10"Na seção
[Strings], remova a linha a seguir.ClassName="Samples" ; TODO: edit ClassName
No arquivo INF, defina a classe de dispositivo do driver como Proximidade:
- Alterar o valor de
ClassparaProximity - Alterar o valor de
ClassGuidpara{5630831C-06C9-4856-B327-F5D32586E060}- Este é o GUID da classe de dispositivo De proximidade.
[Version] ... Class=Proximity ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} ; Proximity class GUID ...- Alterar o valor de
No arquivo INF, adicione uma referência à Extensão de Classe NFC. Isso garante que o WDF (Windows Driver Framework) carregue o driver NFC CX quando o driver cliente for carregado.
- Localize a seção
<project-name>_Install. - Adicione
UmdfExtensions=NfcCx0102.
[<project-name>_Install] ... UmdfExtensions=NfcCx0102- Localize a seção
Nas configurações de build do driver, vincule-se à Extensão de Classe NFC. Isso garante que a API CX nfc esteja disponível durante a compilação de código.
- Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Propriedades. Em Propriedades de Configuração, em Configurações de Driver, selecione NFC.
- Verifique se a configuração está definida como
All Configurations. - Verifique se a Plataforma está definida como
All Platforms. - Definir link para a extensão de classe NFC como
Yes.
Adicione o arquivo com o nome
Driver.cppao projeto.Criar uma
DriverEntryrotina emDriver.cpp. Esse é o ponto de entrada para o driver. Sua principal finalidade é inicializar o WDF e registrar a funçãoEvtDriverDeviceAddde retorno de chamada.#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; }Adicione dois arquivos nomeados
Device.cppeDevice.hao projeto.Em
Device.h, defina aDeviceContextclasse.#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);Em
Device.cpp, inicie a definição de funçãoDeviceContext::AddDevice.#include "Device.h" NTSTATUS DeviceContext::AddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) { NTSTATUS status;Defina a configuração do dispositivo NFC CX. A configuração do dispositivo inclui o fornecimento da função de callback
EvtNfcCxWriteNciPacket. Esse retorno de chamada recebe os pacotes de NCI do driver NFC CX que o driver cliente deve encaminhar para o Controlador 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; }Registre os callbacks de energia PnP necessários para o seu driver cliente.
Um driver cliente típico provavelmente exigirá a
EvtDevicePrepareHardware, aEvtDeviceReleaseHardware, aEvtDeviceD0Entrye aEvtDeviceD0Exit. Os requisitos podem variar dependendo de como o driver cliente lida com o gerenciamento de energia.// 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);Chame a função
WdfDeviceCreatepara criar o objetoWDFDEVICE.// 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; }Chame a função
NfcCxDeviceInitialize.Essa função deve ser chamada depois que o
WDFDEVICEobjeto tiver sido criado para permitir que o driver NFC CX conclua sua inicialização da instância do dispositivo.// Let NFC CX finish initializing the device instance. status = NfcCxDeviceInitialize(device); if (!NT_SUCCESS(status)) { return status; }Chame
NfcCxSetRfDiscoveryConfigpara especificar as tecnologias e os protocolos NFC compatíveis com o controlador 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; }Encerre a função
DeviceContext::AddDevice.return STATUS_SUCCESS; }Implemente as funções de callback
PrepareHardwareeReleaseHardware.Essas duas funções são usadas para inicializar e desinicializar os recursos de hardware atribuídos à instância do dispositivo do Controlador NFC. Sua implementação depende do tipo de barramento ao qual o dispositivo está conectado (por exemplo, I2C, SPI e 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; }Chame a função
NfcCxHardwareEventcomHostActionStarteHostActionStoppara iniciar e parar a máquina de estados NCI nos momentos apropriados.Alguns drivers fazem isso durante os retornos de chamada de energia PnP
D0EntryeD0Exit. No entanto, isso pode variar dependendo de como o driver cliente lida com o gerenciamento de energia.// 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; }Implemente a função
WriteNciPacket.Esse callback é chamado pelo NFC CX quando há um pacote NCI para enviar ao Controlador 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. };Chame a função
NfcCxNciReadNotificationquando o Controlador NFC tiver um pacote NCI que deve ser enviado para o NFC CX. Normalmente, faça isso em um retorno de chamada de evento de hardware.Por exemplo:
- Um callback de evento de interrupção GPIO. (I2C e SPI)
- Um callback de leitor contínuo USB.
Logging
Considere adicionar o registro em log ao driver cliente para facilitar a depuração. O rastreamento de ETW e o rastreamento do WPP são boas opções.