/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxDevice.hpp

Abstract:

    This is the definition of the FxDevice object.

Author:



Environment:

    Both kernel and user mode

Revision History:

--*/

#ifndef _FXDEVICE_H_
#define _FXDEVICE_H_

#include "fxcxdeviceinit.hpp"
#include "fxdeviceinit.hpp"
#include "fxtelemetry.hpp"

struct FxWdmDeviceExtension {
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
    WUDF_IO_REMOVE_LOCK IoRemoveLock;
#else
    IO_REMOVE_LOCK  IoRemoveLock;
#endif
    ULONG           RemoveLockOptionFlags;
};

//
// The following enum is used in serializing packet based DMA transactions.
// According to the DDK docs:
// Only one DMA request can be queued for a device object at any
// one time. Therefore, the driver should not call AllocateAdapterChannel
// again for another DMA operation on the same device object until the
// AdapterControl routine has completed execution. In addition,
// a driver must not call AllocateAdapterChannel from within its
// AdapterControl routine.
//
// This is because when AllocateAdapterChannel blocks waiting for
// map registers, it obtains its wait context block from the device object.
// If AllocateAdapterChannel is then called through a different adapter
// object attached to the same device the wait block will be reused and the
// map register wait list will be corrupted.
//
// For this reason, we need to make sure that for a device used in creating
// DMA enablers, there can be only one packet base DMA transaction
// queued at any one time.
//
// In WDM, one can workaround this limitation by creating dummy deviceobject.
// We can also workaround this limitation by creating a control-device on the
// side for additional enabler objects. Since packet based multi-channel
// devices are rarity these days, IMO, we will defer this feature until there
// is a big demand for it.
//
enum FxDmaPacketTransactionStatus {
    FxDmaPacketTransactionCompleted =0,
    FxDmaPacketTransactionPending,
};

//
// The following enum is used in determining whether the RemLock for a device
// object needs to be held while processing an IRP. For processing certain
// IRPs, it might not be necessary to hold the RemLock, but it might be
// necessary to just test whether the RemLock can be acquired and released.
//
enum FxDeviceRemLockAction {
    FxDeviceRemLockNotRequired = 0,
    FxDeviceRemLockRequired,
    FxDeviceRemLockTestValid,
    FxDeviceRemLockOptIn
};

enum FxPropertyType {
    FxDeviceProperty = 0,
    FxInterfaceProperty,
};

//
// This mask is used to validate the WdfDeviceWdmDispatchIrp's Flags.
//
#define FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK \
    (WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK |\
     WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP)

//
// The following inline functions are used for extracting the normalized file
// object class value and checking the file object class's flags.
//
WDF_FILEOBJECT_CLASS
__inline
FxFileObjectClassNormalize(
    __in WDF_FILEOBJECT_CLASS FileObjectClass
    )
{
    return (WDF_FILEOBJECT_CLASS)(FileObjectClass & ~WdfFileObjectCanBeOptional);
}

BOOLEAN
__inline
FxIsFileObjectOptional(
    __in WDF_FILEOBJECT_CLASS FileObjectClass
    )
{
    return (FileObjectClass & WdfFileObjectCanBeOptional) ? TRUE : FALSE;
}

//
// Base class for all devices.
//
class FxDeviceBase : public FxNonPagedObject, public IFxHasCallbacks {

protected:
    FxDeviceBase(
        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
        __in FxDriver* Driver,
        __in WDFTYPE Type,
        __in USHORT Size
        );

    ~FxDeviceBase(
        VOID
        );

    VOID
    Init(
        __in MdDeviceObject DeviceObject,
        __in MdDeviceObject AttachedDevice,
        __in MdDeviceObject PhysicalDevice
        );

public:
    NTSTATUS
    ConfigureConstraints(
        __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes
        );

    // begin IFxHasCallbacks overrides
    VOID
    GetConstraints(
        __out_opt WDF_EXECUTION_LEVEL*       ExecutionLevel,
        __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
        ) ;

    FxCallbackLock*
    GetCallbackLockPtr(
        __out_opt FxObject** LockObject
        );
    // end IFxHasCallbacks overrides

    __inline
    FxDriver*
    GetDriver(
        VOID
        )
    {
        return m_Driver;
    }


    MdDeviceObject
    __inline
    GetDeviceObject(
        VOID
        )
    {
        return m_DeviceObject.GetObject();
    }

    __inline
    MxDeviceObject*
    GetMxDeviceObject(
        VOID
        )
    {
        return &m_DeviceObject;
    }

    ULONG
    __inline
    GetDeviceObjectFlags(
        VOID
        )
    {
        return m_DeviceObject.GetFlags();
    }

    VOID
    __inline
    SetDeviceObjectFlags(
        _In_ ULONG Flags
        )
    {
        m_DeviceObject.SetFlags(Flags);
    }

    MdDeviceObject
    __inline
    GetAttachedDevice(
        VOID
        )
    {
        return m_AttachedDevice.GetObject();
    }

    ULONG
    __inline
    GetAttachedDeviceObjectFlags(
        VOID
        )
    {
        return m_AttachedDevice.GetFlags();
    }

    MdDeviceObject
    __inline
    GetPhysicalDevice(
        VOID
        )
    {
        return m_PhysicalDevice.GetObject();
    }

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

    virtual
    _Must_inspect_result_
    NTSTATUS
    AddIoTarget(
        __inout FxIoTarget* IoTarget
        )
    {
        UNREFERENCED_PARAMETER(IoTarget);

        //
        // Intentionally does nothing
        //
        return STATUS_SUCCESS;
    }

    virtual
    VOID
    RemoveIoTarget(
        __inout FxIoTarget* IoTarget
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(IoTarget);
    }

    virtual
    _Must_inspect_result_
    NTSTATUS
    AllocateEnumInfo(
        VOID
        )
    {
        return STATUS_SUCCESS;
    }

    virtual
    VOID
    AddChildList(
        __inout FxChildList* List
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(List);
    }

    virtual
    VOID
    RemoveChildList(
        __inout FxChildList* List
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(List);
    }

    virtual
    _Must_inspect_result_
    NTSTATUS
    AllocateDmaEnablerList(
        VOID
        )
    {
        return STATUS_SUCCESS;
    }

    virtual
    VOID
    AddDmaEnabler(
        __inout FxDmaEnabler* Enabler
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(Enabler);
    }

    virtual
    VOID
    RemoveDmaEnabler(
        __inout FxDmaEnabler* Enabler
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(Enabler);
    }

    virtual
    VOID
    SetDeviceTelemetryInfoFlags(
        _In_ FxDeviceInfoFlags Flag
        )
    {
        //
        // Intentionally does nothing
        //
        UNREFERENCED_PARAMETER(Flag);
    }

    __inline
    _Must_inspect_result_
    NTSTATUS
    AcquireDmaPacketTransaction(
        VOID
        )
    {
        //
        // Set the status to Pending only if the previous transaction is Completed.
        //
        if (InterlockedCompareExchange(
                &m_DmaPacketTransactionStatus,
                FxDmaPacketTransactionPending,
                FxDmaPacketTransactionCompleted) == FxDmaPacketTransactionCompleted) {
            return STATUS_SUCCESS;
        } else {
            return STATUS_WDF_BUSY;
        }
    }

    __inline
    VOID
    ReleaseDmaPacketTransaction(
        VOID
        )
    {
        LONG val;

        val = InterlockedExchange(&m_DmaPacketTransactionStatus,
                                  FxDmaPacketTransactionCompleted);

        ASSERT(val == FxDmaPacketTransactionPending); // To catch double release
        UNREFERENCED_PARAMETER(val);
    }

    VOID
    AddToDisposeList(
        __inout FxObject* Object
        )
    {
        m_DisposeList->Add(Object);
    }

    // begin FxObject overrides
    _Must_inspect_result_
    NTSTATUS
    QueryInterface(
        __inout FxQueryInterfaceParams* Params
        );
    // end FxObject overrides

    static
    FxDeviceBase*
    _SearchForDevice(
        __in FxObject* Object,
        __out_opt IFxHasCallbacks** Callbacks
        );

    static
    FxDeviceBase*
    _SearchForDevice(
        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
        __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
        );

    _Must_inspect_result_
    NTSTATUS
    QueryForInterface(
        __in const GUID* InterfaceType,
        __out PINTERFACE Interface,
        __in USHORT Size,
        __in USHORT Version,
        __in PVOID InterfaceSpecificData,
        __in_opt MdDeviceObject TargetDevice = NULL
        );

    __inline
    MdDeviceObject
    GetAttachedDeviceReference(
        VOID
        )
    {
        return Mx::MxGetAttachedDeviceReference(m_DeviceObject.GetObject());
    }

    virtual
    FxIoTarget*
    GetDefaultIoTarget(
        VOID
        )
    {
        return NULL;
    }

    _Must_inspect_result_
    NTSTATUS
    AllocateTarget(
        _Out_ FxIoTarget** Target,
        _In_  BOOLEAN SelfTarget
        );

    //
    // Note: these fields are carefully aligned to minimize space. If you add
    // additional fields make sure to insert them correctly. Always
    // double check your assumptions by loading the amd64 image and
    // comparing the size of this type before and after. For example the
    // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128),
    // a simple change can increase the size by 64/128 bytes.
    //

public:
    //
    // This is used to defer items that must be cleaned up at passive
    // level, and FxDevice waits on this list to empty in DeviceRemove.
    //
    FxDisposeList* m_DisposeList;

protected:
    FxDriver* m_Driver;

    MxDeviceObject m_DeviceObject;
    MxDeviceObject m_AttachedDevice;
    MxDeviceObject m_PhysicalDevice;

    FxCallbackLock* m_CallbackLockPtr;
    FxObject* m_CallbackLockObjectPtr;

    WDF_EXECUTION_LEVEL m_ExecutionLevel;
    WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope;

    //
    // Used to serialize packet dma transactions on this device.
    //
    LONG m_DmaPacketTransactionStatus;
};

class FxDevice : public FxDeviceBase {
   friend VOID GetTriageInfo(VOID);
   friend class FxDriver;
   friend class FxIrp;
   friend class FxFileObject;
   friend class FxPkgPnp;

   //
   // Note: these fields are carefully aligned to minimize space. If you add
   // additional fileds make sure to insert them correctly. Always
   // double check your assumptions by loading the amd64 image and
   // comparing the size of this type before and after. For example the
   // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128),
   // a simple change can increase the size by 64/128 bytes.
   //

private:
    //
    // Maintain the current device states.
    //
    WDF_DEVICE_PNP_STATE            m_CurrentPnpState;
    WDF_DEVICE_POWER_STATE          m_CurrentPowerState;
    WDF_DEVICE_POWER_POLICY_STATE   m_CurrentPowerPolicyState;

    //
    // Store the IO type for read/write
    //
    WDF_DEVICE_IO_TYPE m_ReadWriteIoType;

    //
    // Bit-flags, see FxDeviceCallbackFlags for definitions.
    //
    BYTE m_CallbackFlags;

    // TRUE if a Filter
    BOOLEAN m_Filter;

    //
    // If TRUE, DO_POWER_PAGABLE can be set on m_DeviceObject->Flags if we are
    // not in a special usage path.
    //
    // ***Ignored for filters***
    //
    BOOLEAN m_PowerPageableCapable;

    //
    // TRUE if the parent is removed while the child is still around
    //
    BOOLEAN m_ParentWaitingOnChild;

    //
    // TRUE if the device only allows one create to succeed at any given time
    //
    BOOLEAN m_Exclusive;

    //
    // More deterministic the m_PkgPnp == NULL since m_PkgPnp can be == NULL
    // if there is an allocation failure and during deletion due to insufficient
    // resources we need to know if the device is legacy or not.
    //
    BOOLEAN m_Legacy;

    //
    // If TRUE, m_DeviceObject was deleted in FxDevice::DeleteObject and should
    // not be deleted again later in the destroy path.
    //
    BOOLEAN m_DeviceObjectDeleted;

    //
    // This boost will be used in IoCompleteRequest
    // for read, write and ioctl requests if the client driver
    // completes the request without specifying the boost.
    //
    //
    CHAR m_DefaultPriorityBoost;

    static const CHAR m_PriorityBoosts[];

public:
    //
    // Track the parent if applicable
    //
    CfxDevice *m_ParentDevice;

    //
    // Properties used during Device Creation
    //

    //
    // Store the device name that is used during device creation.
    //
    UNICODE_STRING m_DeviceName;

    UNICODE_STRING m_SymbolicLinkName;

    //
    // Store the name of the resource that is used to store the MOF data
    //
    UNICODE_STRING m_MofResourceName;

    //
    // When reporting a PDO via query device relations, there is a period of
    // time where it is an "official" PDO as recognized by the pnp subsystem.
    // In that period of time, we cannot use the soon to be PDO in any export
    // which expects a PDO as an input parameter.  Once this is set to TRUE,
    // the PDO can be used for such exports.
    //
    // No need to use a lock when comparing against this field.  Once set, it
    // will never revert back to FALSE.
    //
    // This field is always TRUE for FDOs (in relation to the PDO for its stack).
    //
    BOOLEAN m_PdoKnown;

    //
    // If TRUE, then create/cleanup/close are forwarded down the stack
    // If FALSE, then create/cleanup/close are completed at this device
    //
    BOOLEAN m_AutoForwardCleanupClose;

    //
    // If TRUE, an Io Target to the client itself is created to support
    // Self Io Targets.
    //
    BOOLEAN m_SelfIoTargetNeeded;

private:
    //
    // bit-map of device info for Telemetry
    //
    USHORT m_DeviceTelemetryInfoFlags;

public:

    WDF_FILEOBJECT_CLASS m_FileObjectClass;

    FxSpinLockTransactionedList m_IoTargetsList;

    //
    // We'll maintain the prepreocess table "per device" so that it is possible
    // to have different callbacks for each device.
    // Note that each device may be associted with multiple class extension in the future.
    //
    LIST_ENTRY          m_PreprocessInfoListHead;

    //
    // Optional, list of additional class extension settings.
    //
    LIST_ENTRY          m_CxDeviceInfoListHead;

protected:

    //
    // This is used by the FxFileObject class to manage
    // the list of FxFileObject's for this FxDevice
    //
    LIST_ENTRY m_FileObjectListHead;

    //
    // Lookaside list to allocate FxRequests from
    //
    NPAGED_LOOKASIDE_LIST m_RequestLookasideList;

    //
    // Total size of an FxRequest + driver context LookasideList element.
    //
    size_t m_RequestLookasideListElementSize;

    //
    // Object attributes to apply to each FxRequest* returned by
    // m_RequestLookasideList
    //
    WDF_OBJECT_ATTRIBUTES m_RequestAttributes;

public:

    //
    // This is the set of packages used by this device.  I am simply using
    // FxPackage pointers rather than using the actual types because I want
    // to allow fredom for FDOs, PDOs, and control objects to use
    // differnet packages.
    //
    FxPkgIo*            m_PkgIo;
    FxPkgPnp*           m_PkgPnp;
    FxPkgGeneral*       m_PkgGeneral;
    FxWmiIrpHandler*    m_PkgWmi;
    FxDefaultIrpHandler* m_PkgDefault;

    //
    // Note on approaches to having mode-agnoctic code that works for KM and UM
    // and avoids code with lots of #ifdef which becomes a maintenance nightmare.
    // To avoid #ifdef such as below, one approach would have been to have a
    // base class with common data members and virtual funtions , and have
    // derived classes for km and um,each having data members specific to their
    // mode, implementing virtual funcions in mode specific manner. This
    // approach was not taken for following reasons:
    //
    // 1. Avoid confusion between logical hierarchy and organizational hierarchy
    // of objects. E.g. fdo and pdo package is derived from pnp package (logical
    // hierarchy). However, both pdo and fdo package can also be organized into
    // fdokm/fdoum deriving from fdo, and pdokm/pdoum deriving from pdo for km
    // and um flavors, and that would be organizational hierarchy. Mixing these
    // two approaches may create more confusion. If we were to extend the
    // classes in future (for whatever reason), this may become more complex.
    //
    // 2. Even with organizational hierarchy, we need to have #ifdef at the
    // point of creation.
    //
    // Luckily, we don't have many objects that need to be have mode specific
    // data members (currently only FxDevice and interrupt to some extent).
    // Note that member functions are already implemented in mode specific
    // manner, for example, FxDevice::CreateDevice is implemented for UM and KM
    // in FxDeviceUm.cpp and FxDeviceKm.cpp. So #ifdef usage is not a whole lot
    // but we can definitely improve on it.
    //
    // With the current approach, we can do better by avoiding #ifdef as much as
    // possible. We can achieve that with better abstraction, but also having
    // host provide more interfaces so as to mimic closely  those interfaces
    // that kernel provides would also help (this way framework has to maintain
    // less info, because it can always get it from host the way kernel
    // framework would).
    //
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
public:
    //
    // On failed create during AddDevice, KMDF sends a simulated remove event
    // to pnp state machine and thereafter detaches from stack so that windows
    // I/O manager can't send a remove irp. UMDF imitates windows I/O manager
    // in that when AddDevice sent by host is failed by driver, host sends a
    // simulated remove irp to Fx so that it can cleanup.
    //
    // This causes a conflict in merged code because for UMDF,  Fx doesn't
    // detach from stack as part of remove event (since lifetime of umdf stack

    // is controlled by host including detach and deletiton), so unless we
    // prevent, Fx will end up processing remove event twice, once by Pnp sm's
    // simulated event and another by host simulated remove irp.
    //
    // The solution is to allow one remove event to be processed and that would
    // be Fx's remove event (to minimize disparity between KM and UM Fx). The
    // field below tracks the fact that create failed and allows the Fx remove
    // event to be processed and then also allows the device object to detach
    // before returning from failure so that host is not able to send simulated
    // remove to the device.
    //
    BOOLEAN m_CleanupFromFailedCreate;

    //
    // This object implements the IFxMessageDispatch that contains entry points
    // to driver, and is used by host to dispatch irp and other messages.
    //
    FxMessageDispatch* m_Dispatcher;

    //
    //Weak reference to host side device stack
    //
    IWudfDeviceStack*   m_DevStack;

    //
    // PnP devinode hw key handle
    //
    HKEY m_PdoDevKey;

    //
    // Device key registry path
    //
    PWSTR m_DeviceKeyPath;

    //
    // Kernel redirector's side object name.
    //
    PWSTR m_KernelDeviceName;

    //
    // PDO Instance ID
    //
    PWSTR m_DeviceInstanceId;

    //
    // The retrieval mode and i/o type preferences requested
    // by this device. Note that ReadWriteIoType is common to both KMDF and UMDF
    // so no new UM-specific field is required.
    //
    UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL m_RetrievalMode;
    WDF_DEVICE_IO_TYPE             m_IoctlIoType;
    ULONG                          m_DirectTransferThreshold;

    //
    // Tells whether hardware access is allowed.
    //
    WDF_DIRECT_HARDWARE_ACCESS_TYPE m_DirectHardwareAccess;

    //
    // Tells whether hardware register read/write is done using user-mode
    // mapped virtual addresses
    //
    WDF_REGISTER_ACCESS_MODE_TYPE m_RegisterAccessMode;

    //
    // File object policy set through INF directive
    //
    WDF_FILE_OBJECT_POLICY_TYPE m_FileObjectPolicy;

    //
    // Fs context use policy set through INF directive
    //
    WDF_FS_CONTEXT_USE_POLICY_TYPE m_FsContextUsePolicy;

    //
    // Thread pool for interrupt servicing
    //
    FxInterruptThreadpool* m_InteruptThreadpool;

#endif // (FX_CORE_MODE == FX_CORE_USER_MODE)

private:
    //
    // A method called by the constructor(s) to initialize the device state.
    //
    VOID
    SetInitialState(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    PreprocessIrp(
        __in MdIrp Irp
        );

    _Must_inspect_result_
    NTSTATUS
    DeleteDeviceFromFailedCreateNoDelete(
        __in NTSTATUS FailedStatus,
        __in BOOLEAN UseStateMachine
        );

    VOID
    SetFilterIoType(
        VOID
        );

    static
    MdCompletionRoutineType
    _CompletionRoutineForRemlockMaintenance;

    static
    _Must_inspect_result_
    NTSTATUS
    _AcquireOptinRemoveLock(
        __in MdDeviceObject DeviceObject,
        __in MdIrp Irp
        );

    VOID
    DestructorInternal(
        VOID
        );

    NTSTATUS
    WmiPkgRegister(
        VOID
        );

    VOID
    WmiPkgDeregister(
        VOID
        );

    VOID
    WmiPkgCleanup(
        VOID
        );

public:

    FxDevice(
        __in FxDriver *ArgDriver
        );

    ~FxDevice(
        VOID
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _Create(
        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
        __in PWDFDEVICE_INIT* DeviceInit,
        __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,
        __out FxDevice** Device
        );

    _Must_inspect_result_
    NTSTATUS
    DeleteDeviceFromFailedCreate(
        __in NTSTATUS FailedStatus,
        __in BOOLEAN UseStateMachine
        );

    __inline
    FxPackage*
    GetDispatchPackage(
        __in UCHAR MajorFunction
        )
    {
        switch (MajorFunction) {
        case IRP_MJ_CREATE:
        case IRP_MJ_CLOSE:
        case IRP_MJ_CLEANUP:
        case IRP_MJ_SHUTDOWN:
            return (FxPackage*) m_PkgGeneral;

        case IRP_MJ_READ:
        case IRP_MJ_WRITE:
        case IRP_MJ_DEVICE_CONTROL:
        case IRP_MJ_INTERNAL_DEVICE_CONTROL:
            return (FxPackage*) m_PkgIo;

        case IRP_MJ_SYSTEM_CONTROL:
            return (FxPackage*) m_PkgWmi;

        case IRP_MJ_PNP:
        case IRP_MJ_POWER:
            if (m_PkgPnp != NULL) {
                return (FxPackage*) m_PkgPnp;
            }
            else {
                return (FxPackage*) m_PkgDefault;
            }
            break;

        default:
            return (FxPackage*) m_PkgDefault;
        }
    }

    MdRemoveLock
    GetRemoveLock(
        VOID
        );

    static
    FxDeviceRemLockAction
    __inline
    _RequiresRemLock(
        __in UCHAR MajorCode,
        __in UCHAR MinorCode
        )
    {
        switch (MajorCode) {
        //
        // We require remove locks for power irps because they can show
        // up after the device has been removed if the Power subysystem has
        // taken a reference on the device object that raced with the
        // remove irp (or if we are attached above the power policy owner
        // and the power policy owner requests a power irp during remove
        // processing.
        //
        // What it boils down to is that we do it for power because
        // that is the only valid irp which can be sent with an outstanding
        // reference w/out coordination to the device's pnp state.  We
        // assume that for all other irps, the sender has synchronized with
        // the pnp state of the device.
        //
        // We also acquire the remove lock for WMI IRPs because they can
        // come into the stack while we are processing a remove.  For
        // instance, a WMI irp can come into the stack to the attached
        // device before it has a change to process the remove device and
        // unregister with WMI.
        //
        // PNP irps can come in at any time as well.  For instance, query
        // device relations for removal or ejection relations can be sent
        // at any time (and there are pnp stress tests which send them
        // during remove).
        //
        case IRP_MJ_PNP:
            //
            // We special case remove device and only acquire the remove lock
            // in the minor code handler itself.  If handled remove device in
            // the normal way and there was a preprocess routine for it, then
            // we could deadlock if the irp was dispatched back to KMDF in the
            // preprocess routine with an extra outstandling remlock acquire
            // (which won't be released until the preprocess routine returns,
            // which will be too late).
            //
            if (MinorCode == IRP_MN_REMOVE_DEVICE) {
                return FxDeviceRemLockTestValid;
            }
        case IRP_MJ_POWER:
        case IRP_MJ_SYSTEM_CONTROL:
            return FxDeviceRemLockRequired;

        default:
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
            return FxDeviceRemLockOptIn;
#else
            //
            // There is no forseeable scenario where a UMDF driver would need to
            // need to support remove lock for IO IRPs. While this ifdef can be safely
            // removed and UMDF can also return FxDeviceRemLockOptIn, that is
            // being avoided here so that the caller does not need to test the
            // remove lock flags for IO which would never be set.
            //
            return FxDeviceRemLockNotRequired;
#endif
        }
    }

    static
    FxDevice*
    GetFxDevice(
        __in MdDeviceObject DeviceObject
        );

    MdDeviceObject
    __inline
    GetSafePhysicalDevice(
        VOID
        )
    {
        //
        // Makes sure that the PDO we think we have is
        // 1)  reported to pnp (m_PdoKnown check)
        // 2)  actually there (m_PhysicalDevice != NULL check)
        //
        if (m_PdoKnown && m_PhysicalDevice.GetObject() != NULL) {
            return m_PhysicalDevice.GetObject();
        }
        else {
            return NULL;
        }
    }

    static
    _Must_inspect_result_
    NTSTATUS
    STDCALL
    Dispatch(
        __in MdDeviceObject DeviceObject,
        __in MdIrp OriginalIrp
        );

#if (FX_CORE_MODE==FX_CORE_USER_MODE)
    static
    VOID
    DispatchUm(
        _In_ MdDeviceObject DeviceObject,
        _In_ MdIrp Irp,
        _In_opt_ IUnknown* Context
        );

    static
    VOID
    DispatchWithLockUm(
        _In_ MdDeviceObject DeviceObject,
        _In_ MdIrp Irp,
        _In_opt_ IUnknown* Context
        );

    VOID
    SetInterruptThreadpool(
        _In_ FxInterruptThreadpool* Pool
        )
    {
        m_InteruptThreadpool = Pool;
    }

    FxInterruptThreadpool*
    GetInterruptThreadpool(
        VOID
        )
    {
        return m_InteruptThreadpool;
    }

#endif // (FX_CORE_MODE == FX_CORE_USER_MODE)

    static
    _Must_inspect_result_
    NTSTATUS
    STDCALL
    DispatchWithLock(
        __in MdDeviceObject DeviceObject,
        __in MdIrp OriginalIrp
        );

    _Must_inspect_result_
    NTSTATUS
    DispatchPreprocessedIrp(
        __in MdIrp       Irp,
        __in PVOID      DispatchContext
        );

    __inline
    WDF_DEVICE_IO_TYPE
    GetIoType(
        VOID
        )
    {
        return m_ReadWriteIoType;
    }

    __inline
    WDF_DEVICE_IO_TYPE
    GetIoTypeForReadWriteBufferAccess(
        VOID
        )
    {
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
        return m_ReadWriteIoType;
#else
        //
        // For UM, both buffer-copy and direct-access i/o buffer access types
        // follow the same storage and retrieval model in internal structures
        // as in buffered I/O so always return WdfDeviceIoBuffered.
        //
        return WdfDeviceIoBuffered;
#endif
    }

    __inline
    CHAR
    GetDefaultPriorityBoost(
        VOID
        )
    {
        return m_DefaultPriorityBoost;
    }

    //
    // Return FileObjectClass
    //
    __inline
    WDF_FILEOBJECT_CLASS
    GetFileObjectClass(
        VOID
        )
    {
        return m_FileObjectClass;
    }

    //
    // Configuration time fileobject support setting
    //
    __inline
    VOID
    SetFileObjectClass(
        __in WDF_FILEOBJECT_CLASS FileObjectClass
        )
    {
        m_FileObjectClass = FileObjectClass;
    }

    VOID
    InstallPackage(
        __inout FxPackage *Package
        );

    __inline
    WDF_DEVICE_PNP_STATE
    GetDevicePnpState(
        )
    {
        return m_CurrentPnpState;
    }

    __inline
    WDF_DEVICE_POWER_STATE
    GetDevicePowerState(
        )
    {
        return m_CurrentPowerState;
    }

    __inline
    WDF_DEVICE_POWER_POLICY_STATE
    GetDevicePowerPolicyState(
        )
    {
        return m_CurrentPowerPolicyState;
    }

    __inline
    VOID
    SetDevicePnpState(
        __in WDF_DEVICE_PNP_STATE DeviceState
        )
    {
        m_CurrentPnpState = DeviceState;
    }

    __inline
    VOID
    SetDevicePowerState(
        __in WDF_DEVICE_POWER_STATE DeviceState
        )
    {
        m_CurrentPowerState = DeviceState;
    }

    __inline
    VOID
    SetDevicePowerPolicyState(
        __in WDF_DEVICE_POWER_POLICY_STATE DeviceState
        )
    {
        m_CurrentPowerPolicyState = DeviceState;
    }

    __inline
    BOOLEAN
    IsPnp(
        VOID
        )
    {
        return m_PkgPnp != NULL ? TRUE : FALSE;
    }

    __inline
    BOOLEAN
    IsLegacy(
        VOID
        )
    {
        return m_Legacy;
    }

    __inline
    BOOLEAN
    IsExclusive(
        VOID
        )
    {
        return m_Exclusive;
    }

    __inline
    BOOLEAN
    IsFdo(
        VOID
        )
    {
        return m_PkgPnp->GetType() == FX_TYPE_PACKAGE_FDO;
    }

    __inline
    FxPkgFdo*
    GetFdoPkg(
        VOID
        )
    {
        return (FxPkgFdo*) m_PkgPnp;
    }

    __inline
    BOOLEAN
    IsPdo(
        VOID
        )
    {
        return (IsPnp() && m_PkgPnp->GetType() == FX_TYPE_PACKAGE_PDO);
    }

    __inline
    FxPkgPdo*
    GetPdoPkg(
        VOID
        )
    {
        return (FxPkgPdo*) m_PkgPnp;
    }

    _Must_inspect_result_
    NTSTATUS
    CreateDevice(
        __in PWDFDEVICE_INIT DeviceInit
        );

    __inline
    VOID
    SetParentWaitingOnRemoval(
        VOID
        )
    {
        m_ParentWaitingOnChild = TRUE;
    }

    //

    // There are really three steps in device creation.
    //
    //  - Creating the device
    //  - Creating the device object that goes with the device (Initialize)
    //  - Finilizing the initialization after packages are installed, attached,
    //    etc.





    VOID
    FinishInitializing(
        VOID
        );

    VOID
    Destroy(
        VOID
        );

    // <begin> FxObject overrides
    virtual
    VOID
    DeleteObject(
        VOID
        );

    virtual
    BOOLEAN
    Dispose(
        VOID
        );
    // <end> FxObject overrides

    __inline
    PWDF_OBJECT_ATTRIBUTES
    GetRequestAttributes(
        VOID
        )
    {
        return &m_RequestAttributes;
    }

    PVOID
    AllocateRequestMemory(
        __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
        );

    VOID
    FreeRequestMemory(
        __in FxRequest* Request
        );

    // begin FxDeviceBase overrides
    virtual
    _Must_inspect_result_
    NTSTATUS
    AddIoTarget(
        __inout FxIoTarget* IoTarget
        );

    virtual
    VOID
    RemoveIoTarget(
        __inout FxIoTarget* IoTarget
        );

    virtual
    _Must_inspect_result_
    NTSTATUS
    AllocateEnumInfo(
        VOID
        );

    virtual
    VOID
    AddChildList(
        __inout FxChildList* List
        );

    virtual
    VOID
    RemoveChildList(
        __inout FxChildList* List
        );

    virtual
    _Must_inspect_result_
    NTSTATUS
    AllocateDmaEnablerList(
        VOID
        );

    virtual
    VOID
    AddDmaEnabler(
        __inout FxDmaEnabler* Enabler
        );

    virtual
    VOID
    RemoveDmaEnabler(
        __inout FxDmaEnabler* Enabler
        );

    virtual
    FxIoTarget*
    GetDefaultIoTarget(
        VOID
        );

    FxIoTargetSelf*
    GetSelfIoTarget(
        VOID
        );

    virtual
    _Must_inspect_result_
    NTSTATUS
    QueryInterface(
        __inout FxQueryInterfaceParams* Params
        );
    // end FxDeviceBase overrides

    //
    // Filter Driver Support
    //
    __inline
    BOOLEAN
    IsFilter()
    {
        return m_Filter;
    }

    _Must_inspect_result_
    NTSTATUS
    SetFilter(
        __in BOOLEAN Value
        );

    __inline
    BOOLEAN
    IsPowerPageableCapable(
        VOID
        )
    {
        return m_PowerPageableCapable;
    }

    _Must_inspect_result_
    NTSTATUS
    Initialize(
        __in PWDFDEVICE_INIT DeviceInit,
        __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes
        );

    VOID
    ConfigureAutoForwardCleanupClose(
        __in PWDFDEVICE_INIT DeviceInit
        );

    _Must_inspect_result_
    NTSTATUS
    PostInitialize(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    PdoInitialize(
        __in PWDFDEVICE_INIT DeviceInit
        );

    _Must_inspect_result_
    NTSTATUS
    FdoInitialize(
        __in PWDFDEVICE_INIT DeviceInit
        );

    _Must_inspect_result_
    NTSTATUS
    ControlDeviceInitialize(
        __in PWDFDEVICE_INIT DeviceInit
        );

    VOID
    ControlDeviceDelete(
        VOID
        )
    {
        //
        // FxDevice::DeleteObject() has already run, so we must call the super
        // class's version of DeleteObject();
        //
        ASSERT(m_DeviceObjectDeleted);

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

    _Must_inspect_result_
    NTSTATUS
    OpenSettingsKey(
        __out HANDLE* Key,
        __in ACCESS_MASK DesiredAccess = STANDARD_RIGHTS_ALL
        );

    VOID
    DeleteSymbolicLink(
        VOID
        );

    __inline
    BYTE
    GetCallbackFlagsLocked(
        VOID
        )
    {
        return m_CallbackFlags;
    }

    __inline
    BYTE
    GetCallbackFlags(
        VOID
        )
    {
        BYTE flags;
        KIRQL irql;

        Lock(&irql);
        flags =  GetCallbackFlagsLocked();
        Unlock(irql);

        return flags;
    }

    __inline
    VOID
    SetCallbackFlagsLocked(
        __in BYTE Flags
        )
    {
        m_CallbackFlags |= Flags;
    }

    __inline
    VOID
    SetCallbackFlags(
        __in BYTE Flags
        )
    {
        KIRQL irql;

        Lock(&irql);
        SetCallbackFlagsLocked(Flags);
        Unlock(irql);
    }

    __inline
    VOID
    ClearCallbackFlagsLocked(
        __in BYTE Flags
        )
    {
        m_CallbackFlags &= ~Flags;
    }

    __inline
    VOID
    ClearCallbackFlags(
        __in BYTE Flags
        )
    {
        KIRQL irql;

        Lock(&irql);
        ClearCallbackFlagsLocked(Flags);
        Unlock(irql);
    }

    FxCxDeviceInfo*
    GetCxDeviceInfo(
        __in FxDriver*  CxDriver
        )
    {
        FxCxDeviceInfo* cxDeviceInfo;
        PLIST_ENTRY     next;

        //
        // Check if we are using I/O class extensions.
        //
        for (next = m_CxDeviceInfoListHead.Flink;
             next != &m_CxDeviceInfoListHead;
             next = next->Flink) {

            cxDeviceInfo = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry);
            if (cxDeviceInfo->Driver == CxDriver) {
                return cxDeviceInfo;
            }
        }

        return NULL;
    }

    __inline
    BOOLEAN
    IsCxDriverInIoPath(
        __in FxDriver* CxDriver
        )
    {
        return (GetCxDeviceInfo(CxDriver) != NULL) ? TRUE : FALSE;
    }

    __inline
    BOOLEAN
    IsCxInIoPath(
        VOID
        )
    {
        return IsListEmpty(&m_CxDeviceInfoListHead) ? FALSE : TRUE;
    }

#if DBG
    __inline
    FxCxDeviceInfo*
    GetFirstCxDeviceInfo(
        VOID
        )
    {
        if (IsListEmpty(&m_CxDeviceInfoListHead)) {
            return NULL;
        }
        else {
            return CONTAINING_RECORD(m_CxDeviceInfoListHead.Flink,
                                     FxCxDeviceInfo,
                                     ListEntry);
        }
    }

    __inline
    FxCxDeviceInfo*
    GetNextCxDeviceInfo(
        __in FxCxDeviceInfo* CxDeviceInfo
        )
    {
        ASSERT(CxDeviceInfo != NULL);
        if (CxDeviceInfo->ListEntry.Flink == &m_CxDeviceInfoListHead) {
            return NULL;
        }
        else {
            return CONTAINING_RECORD(CxDeviceInfo->ListEntry.Flink,
                                     FxCxDeviceInfo,
                                     ListEntry);
        }
    }

#endif

    __inline
    static
    CCHAR
    GetCxDriverIndex(
        __in FxCxDeviceInfo* CxDeviceInfo
        )
    {
        if (CxDeviceInfo != NULL) {
            return CxDeviceInfo->Index;
        }
        else {
            return 0;
        }
    }

    __inline
    FxDriver*
    GetCxDriver(
        __in FxCxDeviceInfo* CxDeviceInfo
        )
    {
        if (CxDeviceInfo != NULL) {
            return CxDeviceInfo->Driver;
        }
        else {
            return GetDriver();
        }
    }

#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)

    static
    __inline
    NTSTATUS
    _OpenDeviceRegistryKey(
        _In_ MdDeviceObject DeviceObject,
        _In_ ULONG DevInstKeyType,
        _In_ ACCESS_MASK DesiredAccess,
        _Out_ PHANDLE DevInstRegKey
        );

    __inline
    static
    NTSTATUS
    _GetDeviceProperty(
        _In_       MdDeviceObject DeviceObject,
        _In_       DEVICE_REGISTRY_PROPERTY DeviceProperty,
        _In_       ULONG BufferLength,
        _Out_opt_  PVOID PropertyBuffer,
        _Out_      PULONG ResultLength
        );

#elif (FX_CORE_MODE == FX_CORE_USER_MODE)

    static
    NTSTATUS
    _OpenDeviceRegistryKey(
        _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
        _In_ IWudfDeviceStack* DeviceStack,
        _In_ PWSTR DriverName,
        _In_ ULONG DevInstKeyType,
        _In_ ACCESS_MASK DesiredAccess,
        _Out_ PHANDLE DevInstRegKey
        );

    static
    NTSTATUS
    _GetDeviceProperty(
        _In_       PVOID DeviceStack,
        _In_       DEVICE_REGISTRY_PROPERTY DeviceProperty,
        _In_       ULONG BufferLength,
        _Out_opt_  PVOID PropertyBuffer,
        _Out_      PULONG ResultLength
        );

#endif

    static
    _Must_inspect_result_
    NTSTATUS
    _ValidateOpenKeyParams(
        _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _OpenKey(
        _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device,
        _In_ ULONG DeviceInstanceKeyType,
        _In_ ACCESS_MASK DesiredAccess,
        _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes,
        _Out_ WDFKEY* Key
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _AllocAndQueryProperty(
        _In_ PFX_DRIVER_GLOBALS Globals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device,
        _In_opt_ MdDeviceObject RemotePdo,
        _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
        _In_ POOL_TYPE PoolType,
        _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
        _Out_ WDFMEMORY* PropertyMemory
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _QueryProperty(
        _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device,
        _In_opt_ MdDeviceObject RemotePdo,
        _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
        _In_ ULONG BufferLength,
        _Out_opt_ PVOID PropertyBuffer,
        _Out_opt_ PULONG ResultLength
        );

    static
    VOID
    STDCALL
    _InterfaceReferenceNoOp(
        __in_opt PVOID Context
        )
    {
        // NoOp reference stub for query interface
        UNREFERENCED_PARAMETER(Context);
    }

    static
    VOID
    STDCALL
    _InterfaceDereferenceNoOp(
        __in_opt PVOID Context
        )
    {
        // NoOp dereference stub for query interface
        UNREFERENCED_PARAMETER(Context);
    }

    static
    FxWdmDeviceExtension*
    _GetFxWdmExtension(
        __in MdDeviceObject DeviceObject
        );

    BOOLEAN
    IsRemoveLockEnabledForIo(
        VOID
        );

    VOID
    FxLogDeviceStartTelemetryEvent(
        VOID
        )
    {
        // LogDeviceStartTelemetryEvent(GetDriverGlobals(), this); __REACTOS__ : no-op
    }

    virtual
    VOID
    SetDeviceTelemetryInfoFlags(
        _In_ FxDeviceInfoFlags Flag
        )
    {
        m_DeviceTelemetryInfoFlags |= Flag;
    }

    USHORT
    GetDeviceTelemetryInfoFlags(
        VOID
        )
    {
        return m_DeviceTelemetryInfoFlags;
    }

    __inline
    CHAR
    GetStackSize(
        VOID
        )
    {
        return m_DeviceObject.GetStackSize();
    }

    __inline
    VOID
    SetStackSize(
        _In_ CHAR Size
        )
    {
        m_DeviceObject.SetStackSize(Size);
    }

    NTSTATUS
    UpdateInterruptThreadpoolLimits(
        VOID
        )
    {





        return STATUS_SUCCESS;
    }

    FxCmResList*
    GetTranslatedResources(
        )
    {
        return m_PkgPnp->GetTranslatedResourceList();
    }

    VOID
    DetachDevice(
        VOID
        );

    VOID
    InvalidateDeviceState(
        VOID
        );

    NTSTATUS
    CreateSymbolicLink(
        _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
        _In_ PCUNICODE_STRING SymbolicLinkName
        );

    VOID
    SetCleanupFromFailedCreate(
        BOOLEAN Value
        )
    {
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
        m_CleanupFromFailedCreate = Value;
#else
        UNREFERENCED_PARAMETER(Value);
#endif
    }

    BOOLEAN
    IsInterfaceRegistered(
        _In_ const GUID* InterfaceClassGUID,
        _In_opt_ PCUNICODE_STRING RefString
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _AllocAndQueryPropertyEx(
        _In_ PFX_DRIVER_GLOBALS DriverGlobals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device,
        _In_ PVOID PropertyData,
        _In_ FxPropertyType FxPropertyType,
        _In_ POOL_TYPE PoolType,
        _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
        _Out_ WDFMEMORY*  PropertyMemory,
        _Out_ PDEVPROPTYPE PropertyType
        );

    static
    _Must_inspect_result_
    NTSTATUS
    _QueryPropertyEx(
        _In_ PFX_DRIVER_GLOBALS DriverGlobals,
        _In_opt_ PWDFDEVICE_INIT DeviceInit,
        _In_opt_ FxDevice* Device,
        _In_ PVOID PropertyData,
        _In_ FxPropertyType FxPropertyType,
        _In_ ULONG BufferLength,
        _Out_ PVOID PropertyBuffer,
        _Out_ PULONG ResultLength,
        _Out_ PDEVPROPTYPE PropertyType
        );

    _Must_inspect_result_
    NTSTATUS
    OpenDevicemapKeyWorker(
        _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals,
        _In_ PCUNICODE_STRING KeyName,
        _In_ ACCESS_MASK DesiredAccess,
        _In_ FxRegKey* pKey
        );

    _Must_inspect_result_
    NTSTATUS
    AssignProperty (
        _In_ PVOID PropertyData,
        _In_ FxPropertyType FxPropertyType,
        _In_ DEVPROPTYPE Type,
        _In_ ULONG BufferLength,
        _In_opt_ PVOID PropertyBuffer
        );

#if (FX_CORE_MODE==FX_CORE_USER_MODE)

    _Must_inspect_result_
    NTSTATUS
    FxValidateInterfacePropertyData(
        _In_ PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData
        );

    VOID
    GetDeviceStackIoType (
        _Out_ WDF_DEVICE_IO_TYPE* ReadWriteIoType,
        _Out_ WDF_DEVICE_IO_TYPE* IoControlIoType
        );

    __inline
    UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL
    GetRetrievalMode(
        VOID
        )
    {
        return m_RetrievalMode;
    }

    __inline
    WDF_DEVICE_IO_TYPE
    GetPreferredRWTransferMode(
        VOID
        )
    {
        return m_ReadWriteIoType;
    }

    __inline
    WDF_DEVICE_IO_TYPE
    GetPreferredIoctlTransferMode(
        VOID
        )
    {
        return m_IoctlIoType;
    }

    __inline
    ULONG
    GetDirectTransferThreshold(
        VOID
        )
    {
        return m_DirectTransferThreshold;
    }

    static
    VOID
    GetPreferredTransferMode(
        _In_ MdDeviceObject DeviceObject,
        _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode,
        _Out_ WDF_DEVICE_IO_TYPE *RWPreference,
        _Out_ WDF_DEVICE_IO_TYPE *IoctlPreference
        );

    NTSTATUS
    ProcessWmiPowerQueryOrSetData (
        _In_ RdWmiPowerAction   Action,
        _Out_ BOOLEAN *         QueryResult
        );

    static
    WUDF_INTERFACE_CONTEXT
    RemoteInterfaceArrival (
        _In_    IWudfDevice *   DeviceObject,
        _In_    LPCGUID         DeviceInterfaceGuid,
        _In_    PCWSTR          SymbolicLink
        );

    static
    void
    RemoteInterfaceRemoval (
        _In_    IWudfDevice *   DeviceObject,
        _In_    WUDF_INTERFACE_CONTEXT RemoteInterfaceID
        );

    static
    void
    PoFxDevicePowerRequired (
        _In_ MdDeviceObject DeviceObject
        );

    static
    void
    PoFxDevicePowerNotRequired (
        _In_ MdDeviceObject DeviceObject
        );

    static
    BOOL
    TransportQueryId (
        _In_    IWudfDevice *   DeviceObject,
        _In_    DWORD           Id,
        _In_    PVOID           DataBuffer,
        _In_    SIZE_T          cbDataBufferSize
        );

    static
    NTSTATUS
    NtStatusFromHr (
        _In_ IWudfDeviceStack * DevStack,
        _In_ HRESULT Hr
        );

    NTSTATUS
    NtStatusFromHr (
        _In_ HRESULT Hr
        );

    IWudfDeviceStack*
    GetDeviceStack(
        VOID
        );

    IWudfDeviceStack2 *
    GetDeviceStack2(
        VOID
        );

    VOID
    RetrieveDeviceRegistrySettings(
        VOID
        );

    BOOLEAN
    IsDirectHardwareAccessAllowed(
        )
    {
        return (m_DirectHardwareAccess == WdfAllowDirectHardwareAccess);
    }

    BOOLEAN
    IsInterruptAccessAllowed(
        VOID
        )
    {
        //
        // Allow access to interrupts if the device has any connection resources,
        // regardless of the UmdfDirectHardwareAccess INF directive.
        //
        return IsDirectHardwareAccessAllowed() ||
            GetTranslatedResources()->HasConnectionResources();
    }

    BOOLEAN
    AreRegistersMappedToUsermode(
        VOID
        )
    {
        return (m_RegisterAccessMode == WdfRegisterAccessUsingUserModeMapping);
    }

    PVOID
    GetPseudoAddressFromSystemAddress(
        __in PVOID SystemAddress
        )
    {
        return SystemAddress;
    }

    PVOID
    GetSystemAddressFromPseudoAddress(
        __in PVOID PseudoAddress
        )
    {
        return PseudoAddress;
    }

    static
    ULONG
    __inline
    GetLength(
        __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size
        )
    {
        ULONG length = 0;

        switch(Size) {
        case WdfDeviceHwAccessTargetSizeUchar:
            length = sizeof(UCHAR);
            break;
        case WdfDeviceHwAccessTargetSizeUshort:
            length = sizeof(USHORT);
            break;
        case WdfDeviceHwAccessTargetSizeUlong:
            length = sizeof(ULONG);
            break;
        case WdfDeviceHwAccessTargetSizeUlong64:
            length = sizeof(ULONG64);
            break;
        default:
            ASSERT(FALSE);
        }

        return length;
    }

    BOOL
    IsRegister(
        __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type
        )
    {
        if (Type == WdfDeviceHwAccessTargetTypeRegister ||
            Type == WdfDeviceHwAccessTargetTypeRegisterBuffer) {
            return TRUE;
        }

        return FALSE;
    }

    BOOL
    IsPort(
        __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type
        )
    {
        if (Type == WdfDeviceHwAccessTargetTypePort ||
            Type == WdfDeviceHwAccessTargetTypePortBuffer) {
            return TRUE;
        }

        return FALSE;
    }

    BOOL
    IsBufferType(
        __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type
        )
    {
        if (Type == WdfDeviceHwAccessTargetTypeRegisterBuffer ||
            Type == WdfDeviceHwAccessTargetTypePortBuffer) {
            return TRUE;
        }

        return FALSE;
    }

    SIZE_T
    ReadRegister(
        __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size,
        __in PVOID Register
        );

    VOID
    ReadRegisterBuffer(
        __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size,
        __in PVOID Register,
        __out_ecount_full(Count) PVOID Buffer,
        __in ULONG Count
        );

    VOID
    WriteRegister(
        __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size,
        __in PVOID Register,
        __in SIZE_T Value
        );

    VOID
    WriteRegisterBuffer(
        __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size,
        __in PVOID Register,
        __in_ecount(Count) PVOID Buffer,
        __in ULONG Count
        );

    VOID
    RetrieveDeviceInfoRegistrySettings(
        _Out_ PCWSTR* GroupId,
        _Out_ PUMDF_DRIVER_REGSITRY_INFO DeviceRegInfo
        );

#endif // (FX_CORE_MODE == FX_CORE_USER_MODE)

};

class FxMpDevice : public FxDeviceBase {
public:
    FxMpDevice(
        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
        __in FxDriver* Driver,
        __in MdDeviceObject DeviceObject,
        __in MdDeviceObject AttachedDevice,
        __in MdDeviceObject PDO
        ) :
        FxDeviceBase(FxDriverGlobals, Driver, FX_TYPE_MP_DEVICE, sizeof(*this))
    {
        Init(DeviceObject, AttachedDevice, PDO);
        m_DefaultTarget = NULL;

        Mx::MxReferenceObject(m_DeviceObject.GetObject());

        MarkDisposeOverride(ObjectDoNotLock);
    }

    // begin FxObject overrides
    BOOLEAN
    Dispose(
        VOID
        )
    {
        //
        // Important that the cleanup routine be called while the MdDeviceObject
        // is valid!
        //
        CallCleanup();

        //
        // Manually destroy the children now so that by the time we wait on the
        // dispose empty out, all of the children will have been added to it.
        //
        DestroyChildren();

        if (m_DisposeList != NULL) {
            m_DisposeList->WaitForEmpty();
        }

        //
        // No device object to delete since the caller's own the
        // WDM device.  Simulate what FxDevice::Destroy does by NULL'ing out the
        // device objects.
        //
        Mx::MxDereferenceObject(m_DeviceObject.GetObject());
        m_DeviceObject = NULL;
        m_AttachedDevice = NULL;

        return FALSE;
    }
    // end FxObject overrides

    // begin FxDeviceBase overrides
    virtual
    FxIoTarget*
    GetDefaultIoTarget(
        VOID
        )
    {
        return m_DefaultTarget;
    }
    // end FxDeviceBase overrides

public:
    //
    // Default I/O target for this miniport device
    //
    FxIoTarget *m_DefaultTarget;
};

#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
#include "fxdevicekm.hpp"
#else
#include "fxdeviceum.hpp"
#endif


#endif // _FXDEVICE_H_