/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxDriver.hpp

Abstract:

    This is the definition of the FxDriver object.

Author:



Environment:

    Both kernel and user mode

Revision History:

--*/

#ifndef _FXDRIVER_H_
#define _FXDRIVER_H_

#include "fxdrivercallbacks.hpp"


//
// Unique value to retrieve the FxDriver* from the PDEVICE_OBJECT.
//
#define FX_TRACE_INFO_ID   (FxDriver::_GetTraceInfoExtension)

//
// Structure to hold WMI Callback info
//
struct FxTraceInfo {
    MdDriverObject           DriverObject;
    PFN_WDF_TRACE_CALLBACK   Callback;
    PVOID                    Context;
};

//
// Unique value to retrieve the FxDriver* from the MdDriverObject.  Use a value
// that is not exposed to the driver writer through the dispatch table or WDM.
//
#define FX_DRIVER_ID ((PVOID)FxDriver::GetFxDriver)

//
// The following are support classes for FxDriver
//
class FxDriver : public FxNonPagedObject, public IFxHasCallbacks
{
friend class FxDevice;
friend class FxPackage;
friend class FxWmiIrpHandler;

private:

    MxDriverObject m_DriverObject;
    UNICODE_STRING m_RegistryPath;

    BOOLEAN m_DebuggerConnected;

    //
    // Callbacks to device driver
    //
    FxDriverDeviceAdd m_DriverDeviceAdd;

    //
    // This represents any constraints on callbacks
    // to the device driver that may be inherited
    // by child devices and their objects
    //
    WDF_EXECUTION_LEVEL       m_ExecutionLevel;
    WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope;

    //
    // Frameworks objects that raise event callbacks into the device
    // driver provide spinlock and mutex based callback locks
    // to allow proper synchronization between the driver and
    // these callbacks.
    //
    // Some events must be passive level, while others at dispatch
    // level, thus the need for two locks.
    //
    // The objects internal state is protected by the FxNonPagedObject
    // lock inherited by the object, and is different from the callback
    // locks.
    //
    FxCallbackMutexLock m_CallbackMutexLock;

    //
    // These pointers allow the proper lock to be acquired
    // based on the configuration with a minimal of runtime
    // checks. This is configured by ConfigureConstraints()
    //
    FxCallbackLock* m_CallbackLockPtr;
    FxObject*       m_CallbackLockObjectPtr;

    //
    // This is the Driver-wide configuration
    //
    WDF_DRIVER_CONFIG m_Config;

    //
    // Deferred Disposal List
    //
    FxDisposeList*    m_DisposeList;

#if FX_IS_USER_MODE
    //
    // A handle to the driver service parameters key.
    // The framework does not have permission to open it with
    // write access from user mode, so we keep a pre-opened one.
    //
    HKEY m_DriverParametersKey;
#endif

private:

    static
    MdDriverAddDeviceType AddDevice;

public:

    // This is public to allow the C function FxCoreDriverUnload to call it
    FxDriverUnload              m_DriverUnload;

    FxDriver(
        __in MdDriverObject DriverObject,
        __in PWDF_DRIVER_CONFIG DriverConfig,
        __in PFX_DRIVER_GLOBALS FxDriverGlobals
        );

    ~FxDriver();

    static
    VOID
    _InitializeDriverName(
        __in PFX_DRIVER_GLOBALS Globals,
        __in PCUNICODE_STRING RegistryPath
        );

    static
    VOID
    _InitializeTag(
        __in PFX_DRIVER_GLOBALS Globals,
        __in PWDF_DRIVER_CONFIG Config
        );

    static
    FxDriver*
    GetFxDriver(
        __in MdDriverObject DriverObject
        );

    _Must_inspect_result_
    NTSTATUS
    AllocateDriverObjectExtensionAndStoreFxDriver(
        VOID
        );



































    __inline
    WDFDRIVER
    GetHandle(
        VOID
        )
    {
        return (WDFDRIVER) GetObjectHandle();
    }

#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)

    _Must_inspect_result_
    NTSTATUS
    AddDevice(
        __in MdDeviceObject PhysicalDeviceObject
        );

#else

    _Must_inspect_result_
    NTSTATUS
    FxDriver::AddDevice(
        _In_  IWudfDeviceStack *        DevStack,
        _In_  LPCWSTR                   KernelDeviceName,
        _In_opt_ HKEY                   PdoKey,
        _In_  LPCWSTR                   ServiceName,
        _In_  LPCWSTR                   DevInstanceID,
        _In_  ULONG                     DriverID
        );
#endif

    VOID
    InitializeInternal(
        VOID
        );

    _Must_inspect_result_
    FxString *
    GetRegistryPath(
        VOID
        );

    PUNICODE_STRING
    GetRegistryPathUnicodeString(
        VOID
        )
    {
        return &m_RegistryPath;
    }

    __inline
    MdDriverObject
    GetDriverObject(
        VOID
        )
    {
        return m_DriverObject.GetObject();
    }

    _Must_inspect_result_
    NTSTATUS
    Initialize(
        __in PCUNICODE_STRING RegistryPath,
        __in PWDF_DRIVER_CONFIG Config,
        __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
        );

    //
    // The following methods support the callback constraints
    // and handle locking and deferral
    //
    VOID
    ConfigureConstraints(
        __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
        );

    //
    // IFxHasCallbacks Support
    //

    virtual
    VOID
    GetConstraints(
        __out WDF_EXECUTION_LEVEL*       ExecutionLevel,
        __out WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
        ) {

        if (ExecutionLevel != NULL) {
            *ExecutionLevel = m_ExecutionLevel;
        }

        if (SynchronizationScope != NULL) {
            *SynchronizationScope = m_SynchronizationScope;
        }
    }

    virtual
    FxCallbackLock*
    GetCallbackLockPtr(
        __deref_out FxObject** LockObject
        ) {

        if (LockObject != NULL) {
            *LockObject = m_CallbackLockObjectPtr;
        }

        return m_CallbackLockPtr;
    }

    //
    // IFxAssociation Support
    //
    virtual
    NTSTATUS
    QueryInterface(
        __inout FxQueryInterfaceParams* Params
        )
    {
        switch (Params->Type) {
        case FX_TYPE_DRIVER:
            *Params->Object = (FxDriver*) this;
            break;

        default:
            return FxNonPagedObject::QueryInterface(Params); // __super call
        }

        return STATUS_SUCCESS;
    }

    virtual
    VOID
    DeleteObject(
        VOID
        )
    {
        //
        // If diposed at > PASSIVE, we will cause a deadlock in FxDriver::Dispose
        // when we call into  the dispose list to wait for empty when we are in
        // the context of the dispose list's work item.
        //
        ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);

        FxNonPagedObject::DeleteObject(); // __super call
    }

    virtual
    BOOLEAN
    Dispose(
        VOID
        );

    __inline
    FxDisposeList*
    GetDisposeList(
        )
    {
        return m_DisposeList;
    }

    __inline
    PFN_WDF_DRIVER_DEVICE_ADD
    GetDriverDeviceAddMethod(
        )
    {
        return m_DriverDeviceAdd.Method;
    }

    static
    MdDriverUnloadType Unload;

#if FX_IS_USER_MODE
private:

    //
    // Open the handle to the driver service parameters key
    // that we keep opened for use from user mode.
    //
    NTSTATUS
    OpenParametersKey(
        VOID
        );

    VOID
    ClearDriverObjectFxDriver(
        VOID
        );

public:

    __inline
    HKEY
    GetDriverParametersKey(
        VOID
        )
    {
        return m_DriverParametersKey;
    }
#endif

#if (FX_CORE_MODE == FX_CORE_USER_MODE)

    VOID
    SetDriverObjectFlag(
        _In_ FxDriverObjectUmFlags Flag
        )
    {
        m_DriverObject.SetDriverObjectFlag(Flag);
    }

    BOOLEAN
    IsDriverObjectFlagSet(
        _In_ FxDriverObjectUmFlags Flag
        )
    {
        return m_DriverObject.IsDriverObjectFlagSet(Flag);
    }

#endif

};

#endif // _FXDRIVER_H_