Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En esta guía se muestra cómo escribir un controlador funcional NFC mediante el controlador de extensión de clase NFC (NFC CX).
Note
Un controlador que usa un controlador de extensión de clase en su implementación se conoce como "controlador cliente". Es decir, un cliente del controlador de extensión de clase.
Prerequisites
- El firmware del controlador NFC debe implementar el protocolo NFC Controller Interface (NCI) de NFC Forum.
- Visual Studio 2017 (o posterior).
- El Windows SDK.
- El Kit para controladores de Windows (WDK).
Responsabilidades del conductor del cliente
El controlador NFC CX es responsable de controlar las solicitudes de E/S enviadas al controlador y crear los paquetes de comandos de NCI pertinentes. El controlador cliente es responsable de enviar esos paquetes NCI al controlador NFC y devolver los paquetes de respuesta de NCI al controlador NFC CX.
Depende del controlador cliente determinar cómo enviar los paquetes de NCI al controlador NFC. Este proceso varía en función del tipo de bus de hardware que se use. Los buses comunes usados por los controladores NFC incluyen I2C, SPI y USB.
Código completo del proyecto
Hay disponible una versión completa de este código de ejemplo en GitHub: NFC CX client driver sample.
Configuración del proyecto
En Visual Studio, cree un nuevo proyecto "User Mode Driver, Empty (UMDF V2)".
En el menú Archivo , seleccione Nuevoy haga clic en Proyecto. En el nodo Visual C++, en Controladores de Windows, seleccione WDF y, a continuación, seleccione Controlador del modo de usuario, Vacío (UMDF V2)
Abra el archivo INF.
En Explorador de soluciones, en el nodo <project-name>, en la carpeta Archivos de controlador, haga doble clic en <project-name>.inf.
En el archivo INF, quite la clase de dispositivo personalizada mediante los pasos siguientes:
Quite las dos secciones siguientes:
[ClassInstall32] AddReg=SampleClass_RegistryAdd [SampleClass_RegistryAdd] HKR,,,,%ClassName% HKR,,Icon,,"-10"En la
[Strings]sección , quite la línea siguiente.ClassName="Samples" ; TODO: edit ClassName
En el archivo INF, establezca la clase de dispositivo del controlador en Proximidad:
- Cambiar el valor de
ClassaProximity - Cambiar el valor de
ClassGuida{5630831C-06C9-4856-B327-F5D32586E060}- Este es el GUID de la clase de dispositivo De proximidad.
[Version] ... Class=Proximity ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} ; Proximity class GUID ...- Cambiar el valor de
En el archivo INF, agregue una referencia a la extensión de clase NFC. Esto garantiza que Windows Driver Framework (WDF) cargue el controlador NFC CX cuando se cargue el controlador cliente.
- Busque la sección
<project-name>_Install. - Agregue
UmdfExtensions=NfcCx0102.
[<project-name>_Install] ... UmdfExtensions=NfcCx0102- Busque la sección
En la configuración de compilación del controlador, vincule a la extensión de clase NFC. Esto garantiza que la API NFC CX esté disponible durante la compilación de código.
- En Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Propiedades. En Propiedades de configuración, en Configuración del controlador, seleccione NFC.
- Asegúrese de que Configuration está establecido en
All Configurations. - Asegúrese de que Platform esté configurado en
All Platforms. - Configure Vínculo a extensión de clase NFC a
Yes.
Agregue el archivo denominado
Driver.cppal proyecto.Cree una
DriverEntryrutina enDriver.cpp. Este es el punto de entrada del driver. Su propósito principal es inicializar WDF y registrar laEvtDriverDeviceAddfunción de devolución de llamada.#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; }Agregue dos archivos denominados
Device.cppyDevice.hal proyecto.En
Device.h, defina laDeviceContextclase .#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);En
Device.cpp, inicie la definición de laDeviceContext::AddDevicefunción.#include "Device.h" NTSTATUS DeviceContext::AddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) { NTSTATUS status;Establezca la configuración del dispositivo NFC CX. La configuración del dispositivo incluye proporcionar la función
EvtNfcCxWriteNciPacketde devolución de llamada. Esta función de devolución de llamada recibe los paquetes NCI del controlador NFC CX que el controlador cliente debe reenviar al dispositivo 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 los callbacks de administración de energía de PnP requeridos por el controlador del cliente.
Es probable que un controlador de cliente típico requiera las funciones
EvtDevicePrepareHardware,EvtDeviceReleaseHardware,EvtDeviceD0EntryyEvtDeviceD0Exit. Los requisitos pueden variar en función de cómo el controlador cliente administra la energía.// 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);Llame a la función
WdfDeviceCreatepara crear el 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; }Llame a la función
NfcCxDeviceInitialize.Se debe llamar a esta función después de crear el
WDFDEVICEobjeto para permitir que el controlador NFC CX complete su inicialización de la instancia del dispositivo.// Let NFC CX finish initializing the device instance. status = NfcCxDeviceInitialize(device); if (!NT_SUCCESS(status)) { return status; }Llame
NfcCxSetRfDiscoveryConfigpara especificar las tecnologías y protocolos NFC compatibles con el 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; }Finalice la
DeviceContext::AddDevicefunción.return STATUS_SUCCESS; }Implemente las funciones de devolución de llamada
PrepareHardwareyReleaseHardware.Estas dos funciones se usan para inicializar y desinicializar los recursos de hardware asignados a la instancia de dispositivo del controlador NFC. Su implementación depende del tipo de bus al que está conectado el dispositivo (por ejemplo, I2C, SPI y 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; }Llame a la
NfcCxHardwareEventfunción conHostActionStartyHostActionStoppara iniciar y detener la máquina de estado de la NCI en los momentos adecuados.Algunos controladores lo hacen durante los callbacks de energía de PnP
D0EntryyD0Exit. Esto puede variar en función del modo en que el controlador cliente controle la administración de energía, sin embargo.// 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 la
WriteNciPacketfunción .Esta devolución de llamada es invocada por NFC CX cuando hay un paquete NCI que se va a enviar al 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. };Llame a la
NfcCxNciReadNotificationfunción cuando el controlador NFC tenga un paquete NCI que se debe enviar al NFC CX. Normalmente, haga esto en un callback de evento de hardware.Por ejemplo:
- Función de devolución de llamada de evento de interrupción GPIO. (I2C y SPI)
- Una retrollamada de lector continuo USB.
Logging
Considere la posibilidad de agregar el registro al driver del cliente para facilitar la depuración. Tanto el seguimiento ETW como el seguimiento de WPP son buenas opciones.