/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxWmiIrpHandler.hpp

Abstract:

    This module implements the wmi IRP handler for the driver frameworks.

Author:



Environment:

    Both kernel and user mode

Revision History:


--*/

#ifndef _FXWMIIRPHANDLER_H_
#define _FXWMIIRPHANDLER_H_

typedef
_Must_inspect_result_
NTSTATUS
(*PFN_WMI_HANDLER_MINOR_DISPATCH)(
    __in FxWmiIrpHandler* This,
    __in PIRP Irp,
    __in FxWmiProvider* Provider,
    __in FxWmiInstance* Instance
    );

struct FxWmiMinorEntry {
    __in PFN_WMI_HANDLER_MINOR_DISPATCH Handler;
    __in BOOLEAN CheckInstance;
};

class FxWmiIrpHandler : public FxPackage {
    friend FxWmiProvider;

public:

    FxWmiIrpHandler(
        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
        __in CfxDevice *Device,
        __in WDFTYPE Type = FX_TYPE_WMI_IRP_HANDLER
        );

    ~FxWmiIrpHandler();

    _Must_inspect_result_
    NTSTATUS
    PostCreateDeviceInitialize(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    HandleWmiTraceRequest(
        __in PIRP Irp,
        __in FxTraceInfo* Info
        );

    virtual
    _Must_inspect_result_
    NTSTATUS
    Dispatch(
        __in PIRP Irp
        );

    _Must_inspect_result_
    NTSTATUS
    Register(
        VOID
        );

    VOID
    Deregister(
        VOID
        );

    VOID
    Cleanup(
        VOID
        );

    VOID
    ResetStateForPdoRestart(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    AddProvider(
        __in FxWmiProvider* Provider,
        __out_opt PBOOLEAN Update = NULL
        );

    _Must_inspect_result_
    NTSTATUS
    AddPowerPolicyProviderAndInstance(
        __in    PWDF_WMI_PROVIDER_CONFIG ProviderConfig,
        __in    FxWmiInstanceInternalCallbacks* Callbacks,
        __inout FxWmiInstanceInternal** Instance
        );

protected:
    static
    VOID
    CheckAssumptions(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    AddProviderLocked(
        __in FxWmiProvider* Provider,
        __in KIRQL Irql,
        __out_opt PBOOLEAN Update = NULL
        );

    VOID
    RemoveProvider(
        __in FxWmiProvider* Provider
        );

    VOID
    RemoveProviderLocked(
        __in FxWmiProvider* Provider
        );

    _Must_inspect_result_
    FxWmiProvider*
    FindProviderLocked(
        __in LPGUID Guid
        );

    _Must_inspect_result_
    FxWmiProvider*
    FindProviderReferenced(
        __in LPGUID Guid,
        __in PVOID Tag
        );

private:
    static
    _Must_inspect_result_
    NTSTATUS
    _QueryAllData(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in_opt FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _QuerySingleInstance(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _ChangeSingleInstance(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _ChangeSingleItem(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _EnableDisableEventsAndCollection(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _RegInfo(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in_opt FxWmiProvider* Provider,
        __in_opt FxWmiInstance* Instance
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _ExecuteMethod(
        __in FxWmiIrpHandler* This,
        __in PIRP Irp,
        __in FxWmiProvider* Provider,
        __in FxWmiInstance* Instance
        );

    VOID
    CompleteWmiQueryAllDataRequest(
        __in PIRP Irp,
        __in NTSTATUS Status,
        __in ULONG BufferUsed
        );

    VOID
    CompleteWmiQuerySingleInstanceRequest(
        __in PIRP Irp,
        __in NTSTATUS Status,
        __in ULONG BufferUsed
        );

    VOID
    CompleteWmiExecuteMethodRequest(
        __in PIRP Irp,
        __in NTSTATUS Status,
        __in ULONG BufferUsed
        );

    _Must_inspect_result_
    NTSTATUS
    CompleteWmiRequest(
        __in PIRP Irp,
        __in NTSTATUS Status,
        __in ULONG BufferUsed
        );

    BOOLEAN
    DeferUpdateLocked(
        __in KIRQL OldIrql
        );

    static
    MX_WORKITEM_ROUTINE _UpdateGuids;

    VOID
    UpdateGuids(
        VOID
        );

    VOID
    IncrementUpdateCount() {
        LONG count;

        count = InterlockedIncrement(&m_UpdateCount);
        ASSERT(count > 1);
        UNREFERENCED_PARAMETER(count);
    }

    VOID
    DecrementUpdateCount() {
        LONG count;

        count = InterlockedDecrement(&m_UpdateCount);
        ASSERT(count >= 0);
        if (count == 0) {
            m_UpdateEvent.Set();
        }
    }

    VOID
    DecrementUpdateCountAndWait() {

        DecrementUpdateCount();

        m_UpdateEvent.EnterCRAndWaitAndLeave();
    }

protected:
    enum WmiRegisteredState {
        WmiUnregistered = 0,
        WmiRegistered,
        WmiDeregistered,
        WmiCleanedUp
    };

protected:
    static const FxWmiMinorEntry m_WmiDispatchTable[];

    LIST_ENTRY m_ProvidersListHead;

    ULONG m_NumProviders;

    WmiRegisteredState m_RegisteredState;

    PIO_WORKITEM m_WorkItem;

    //
    // count of references taken every time an update is needed
    //
    LONG m_UpdateCount;

    //
    // WMI unregister waits on this event to ensure no upadtes are allowed
    // after unregister.
    //
    FxCREvent m_UpdateEvent;

    PKEVENT m_WorkItemEvent;

    BOOLEAN m_WorkItemQueued;


};

#endif // _FXWMIIRPHANDLER_H_