Guía de inicio rápido de NFC CX

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

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

  1. 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)

    Captura de pantalla que muestra el cuadro de diálogo

  2. 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.

  3. En el archivo INF, quite la clase de dispositivo personalizada mediante los pasos siguientes:

    1. Quite las dos secciones siguientes:

      [ClassInstall32]
      AddReg=SampleClass_RegistryAdd
      
      [SampleClass_RegistryAdd]
      HKR,,,,%ClassName%
      HKR,,Icon,,"-10"
      
    2. En la [Strings] sección , quite la línea siguiente.

      ClassName="Samples" ; TODO: edit ClassName
      
  4. En el archivo INF, establezca la clase de dispositivo del controlador en Proximidad:

    1. Cambiar el valor de Class a Proximity
    2. Cambiar el valor de ClassGuid a {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
    ...
    
  5. 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.

    1. Busque la sección <project-name>_Install.
    2. Agregue UmdfExtensions=NfcCx0102.
    [<project-name>_Install]
    ...
    UmdfExtensions=NfcCx0102
    
  6. 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.

    1. 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.
    2. Asegúrese de que Configuration está establecido en All Configurations.
    3. Asegúrese de que Platform esté configurado en All Platforms.
    4. Configure Vínculo a extensión de clase NFC a Yes.

    Visual Studio cuadro de diálogo: Páginas de propiedades de MyNfcDriver, que muestra

  7. Agregue el archivo denominado Driver.cpp al proyecto.

  8. Cree una DriverEntry rutina en Driver.cpp. Este es el punto de entrada del driver. Su propósito principal es inicializar WDF y registrar la EvtDriverDeviceAdd funció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;
    }
    
  9. Agregue dos archivos denominados Device.cpp y Device.h al proyecto.

  10. En Device.h, defina la DeviceContext clase .

    #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);
    
  11. En Device.cpp, inicie la definición de la DeviceContext::AddDevice función.

    #include "Device.h"
    
    NTSTATUS DeviceContext::AddDevice(
        _In_ WDFDRIVER Driver,
        _Inout_ PWDFDEVICE_INIT DeviceInit)
    {
        NTSTATUS status;
    
    
  12. Establezca la configuración del dispositivo NFC CX. La configuración del dispositivo incluye proporcionar la función EvtNfcCxWriteNciPacket de 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;
        }
    
  13. 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, EvtDeviceD0Entry y EvtDeviceD0Exit. 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);
    
  14. Llame a la función WdfDeviceCreate para crear el objeto 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;
        }
    
  15. Llame a la función NfcCxDeviceInitialize.

    Se debe llamar a esta función después de crear el WDFDEVICE objeto 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;
        }
    
  16. Llame NfcCxSetRfDiscoveryConfig para 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;
        }
    
  17. Finalice la DeviceContext::AddDevice función.

        return STATUS_SUCCESS;
    }
    
  18. Implemente las funciones de devolución de llamada PrepareHardware y ReleaseHardware.

    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;
    }
    
  19. Llame a la NfcCxHardwareEvent función con HostActionStart y HostActionStop para 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 D0Entry y D0Exit. 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;
    }
    
  20. Implemente la WriteNciPacket funció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.
    };
    
  21. Llame a la NfcCxNciReadNotification funció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:

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.