NTSTATUS
NfcCxEvtSetLlcpConfig(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE Device,
    _In_ PCNFC_CX_LLCP_CONFIG Config
    )
/*++

Routine Description:

    This routine is called by the CX client to configure
    the RF discovery settings.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    Config - Pointer to a structure containing the LLCP configuration

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    PNFCCX_FDO_CONTEXT fdoContext;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    if (!VerifyPrivateGlobals(NfcCxGlobals)) {
        TRACE_LINE(LEVEL_ERROR, "Invalid CX global pointer");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    if (NULL == Config ||
        sizeof(*Config) != Config->Size) {
        TRACE_LINE(LEVEL_ERROR, "Invalid Client Driver Configuration");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    fdoContext = NfcCxFdoGetContext(Device);

    if (fdoContext->RFInterface == NULL) {
        TRACE_LINE(LEVEL_ERROR, "CX not initialized");
        status = STATUS_INVALID_DEVICE_STATE;
        goto Done;
    }

    status = NfcCxRFInterfaceSetLLCPConfig(fdoContext->RFInterface, Config);

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}
VOID
NfcCxSCPresentAbsentDispatcherRequestCanceled(
    _In_ WDFREQUEST Request
    )
/*++

Routine Description:

    Called when a pending request has been canceled.

Arguments:

    Request - The request

Return Value:

    NTSTATUS

--*/
{
    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request);
    WDFDEVICE device = WdfFileObjectGetDevice(fileObject);

    PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject);
    PNFCCX_FDO_CONTEXT fdoContext = NfcCxFdoGetContext(device);
    PNFCCX_SC_REQUEST_CONTEXT requestContext = NfcCxSCGetRequestContext(Request);
    PNFCCX_SC_PRESENT_ABSENT_DISPATCHER dispatcher = requestContext->Dispatcher;

    // Remove this request from the dispatcher
    void* previousRequest = InterlockedCompareExchangePointer((void**)&dispatcher->CurrentRequest, /*exchange*/ nullptr, /*compare*/ Request);

    // Check if another thread has already completed the request.
    if (previousRequest != Request)
    {
        // Request already completed by a different thread.
        // Nothing to do.
        goto Done;
    }

    // Release power reference (if required).
    if (dispatcher->PowerManaged)
    {
        NfcCxPowerFileRemoveReference(fdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity);
    }

    // Complete the request.
    TRACE_LINE(LEVEL_ERROR, "Smartcard Present/Absent request canceled. %!STATUS!", STATUS_CANCELLED);
    WdfRequestComplete(Request, STATUS_CANCELLED);

Done:
    // Release the cancel callback's extra ref-count
    WdfObjectDereference(Request);

    TRACE_FUNCTION_EXIT(LEVEL_VERBOSE);
}
NTSTATUS
NfcCxEvtDeviceDeinitialize(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE Device
    )
/*++

Routine Description:

    This routine is called by the CX client to indicate
    that a device deinitialization is required.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    PNFCCX_FDO_CONTEXT fdoContext;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    if (!VerifyPrivateGlobals(NfcCxGlobals)) {
        TRACE_LINE(LEVEL_ERROR, "Invalid CX global pointer");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    fdoContext = NfcCxFdoGetContext(Device);

    status = NfcCxFdoCleanup(fdoContext);
    if (!NT_SUCCESS(status)) {
        TRACE_LINE(LEVEL_ERROR, "Failed to cleanup the Fdo context failed %!STATUS!", status);
        goto Done;
    }

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    TRACE_LOG_NTSTATUS_ON_FAILURE(status);
    
    return status;
}
NTSTATUS
NfcCxEvtUnregisterSequenceHandler(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE Device,
    _In_ NFC_CX_SEQUENCE Sequence
    )
/*++

Routine Description:

    This routine is called by the CX client to unregister
    a previously registered sequence handler

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    Sequence - The sequence to unregister

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    PNFCCX_FDO_CONTEXT fdoContext;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    if (!VerifyPrivateGlobals(NfcCxGlobals)) {
        TRACE_LINE(LEVEL_ERROR, "Invalid CX global pointer");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    if (SequenceMaximum <= Sequence) {
        TRACE_LINE(LEVEL_ERROR, "Invalid Client Driver Parameters");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    fdoContext = NfcCxFdoGetContext(Device);

    if (fdoContext->RFInterface == NULL) {
        TRACE_LINE(LEVEL_ERROR, "CX not initialized");
        status = STATUS_INVALID_DEVICE_STATE;
        goto Done;
    }

    TraceLoggingWrite(
        g_hNfcCxProvider,
        "NfcCxEvtUnregisterSequence",
        TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY),
        TraceLoggingValue((DWORD)Sequence, "sequence"));

    status = NfcCxRFInterfaceUnregisterSequenceHandler(fdoContext->RFInterface, Sequence);

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}
NTSTATUS
NfcCxEvtNciReadNotification(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE    Device,
    _In_ WDFMEMORY    Memory
    )
/*++

Routine Description:

    This routine is called by the CX client to signal a
    read notification.  The implementation of this function forwards
    the content of the notification to the Tml layer which will complete
    a pended read request up to the NfcLib.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    Memory - A pointer to a WDFMEMORY object that contains the 
             content of the read notification

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    
    PUCHAR buffer = NULL;
    size_t bufferSize = 0;

    UNREFERENCED_PARAMETER(NfcCxGlobals);

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    buffer = (PUCHAR)WdfMemoryGetBuffer(Memory, &bufferSize);

    if (MAX_USHORT < bufferSize) {
        TRACE_LINE(LEVEL_ERROR, "Invalid read notification sent, ignoring!!!");
        NT_ASSERTMSG("ReadNotification too large", FALSE);
        goto Done;
    }

    //
    // Forward the read to the Tml interface
    //
    status = NfcCxTmlDispatchReadNotification((NfcCxFdoGetContext(Device))->TmlInterface,
                                              buffer,
                                              (USHORT)bufferSize);
    if (!NT_SUCCESS(status)) {
        TRACE_LINE(LEVEL_ERROR, "Failed to dispatch read notification, %!STATUS!", status);
        goto Done;
    }

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}
NTSTATUS
NfcCxEvtHardwareEvent(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE Device,
    _In_ PNFC_CX_HARDWARE_EVENT NciCxHardwareEventParams
    )
/*++

Routine Description:

    This routine is called by the CX client to indicate
    that a Hardware Event has occured.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    NciCxHardwareEventParams - A pointer to a hardware event description structure

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    PNFCCX_FDO_CONTEXT fdoContext;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    if (!VerifyPrivateGlobals(NfcCxGlobals)) {
        TRACE_LINE(LEVEL_ERROR, "Invalid CX global pointer");
        status = STATUS_INVALID_PARAMETER;
        goto Done;
    }

    fdoContext = NfcCxFdoGetContext(Device);

    TRACE_LINE(LEVEL_INFO, "Client signalled an event, %!STATUS!, %!NFC_CX_HOST_ACTION!", 
                NciCxHardwareEventParams->HardwareStatus,
                NciCxHardwareEventParams->HostAction);

    switch (NciCxHardwareEventParams->HostAction) {
    case HostActionStart:
        status = NfcCxFdoInitialize(fdoContext);
        if (!NT_SUCCESS(status)) {
            NfcCxFdoDeInitialize(fdoContext);
            TRACE_LINE(LEVEL_ERROR, "Failed to initialize the Fdo, %!STATUS!", status);
            goto Done;
        }
        break;
    case HostActionStop:
        status = NfcCxFdoDeInitialize(fdoContext);
        if (!NT_SUCCESS(status)) {
            TRACE_LINE(LEVEL_ERROR, "Failed to NfcCxFdoDeInitialize the Fdo, %!STATUS!", status);
            goto Done;
        }
        break;
    case HostActionRestart:
        WdfDeviceSetFailed(Device, WdfDeviceFailedAttemptRestart);
        break;
    case HostActionUnload:
        WdfDeviceSetFailed(Device, WdfDeviceFailedNoRestart);
        break;
    default:
        TRACE_LINE(LEVEL_ERROR, "Invalid Host Action %d", NciCxHardwareEventParams->HostAction);
        break;
    }

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    TRACE_LOG_NTSTATUS_ON_FAILURE(status);

    return status;
}