[WDF] Add Windows Driver Framework files
[reactos.git] / sdk / lib / drivers / wdf / shared / inc / private / common / fxioqueue.hpp
diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueue.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueue.hpp
new file mode 100644 (file)
index 0000000..ed403db
--- /dev/null
@@ -0,0 +1,1714 @@
+
+/*++
+
+Copyright (c) Microsoft. All rights reserved.
+
+Module Name:
+
+    FxIoQueue.h
+
+Abstract:
+
+    This module implements the I/O package queue object
+
+Author:
+
+
+
+
+Environment:
+
+    Both kernel and user mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _FXIOQUEUE_H_
+#define _FXIOQUEUE_H_
+
+#include "FxIoQueueCallbacks.hpp"
+
+extern "C" {
+#if defined(EVENT_TRACING)
+#include "FxIoQueue.hpp.tmh"
+#endif
+}
+
+
+//
+// These FxIoQueue public Enum and Struct are used to tie the queue
+// with FxPkgIo.
+//
+enum FxIoQueueNodeType {
+    FxIoQueueNodeTypeInvalid = 0,
+    FxIoQueueNodeTypeQueue,
+    FxIoQueueNodeTypeBookmark,
+    FxIoQueueNodeTypeLast,
+};
+
+struct FxIoQueueNode {
+public:
+    //
+    // Data members.
+    //
+    LIST_ENTRY          m_ListEntry;
+    FxIoQueueNodeType   m_Type;
+
+public:
+    //
+    // Manager functions.
+    //
+    FxIoQueueNode(
+        FxIoQueueNodeType NodeType
+        ) :
+        m_Type(NodeType)
+    {
+        ASSERT(_IsValidNodeType(m_Type));
+        InitializeListHead(&m_ListEntry);
+    }
+
+    ~FxIoQueueNode()
+    {
+        ASSERT(IsListEmpty(&m_ListEntry) == TRUE);
+    }
+
+private:
+    //
+    // Turn off unsupported manager functions.
+    //
+    FxIoQueueNode();
+
+    //
+    // Block default behavior to shallow copy the object because it contains
+    // a double-link entry; shallow copying the object produces an invalid
+    // copy because the double-link entry is not properly re-initialized.
+    //
+    FxIoQueueNode(const FxIoQueueNode&);
+
+    FxIoQueueNode& operator=(const FxIoQueueNode&);
+
+public:
+    //
+    // Helper functions.
+    //
+    static
+    FxIoQueueNode*
+    _FromListEntry(
+        __in PLIST_ENTRY Entry
+        )
+    {
+        return CONTAINING_RECORD(Entry, FxIoQueueNode, m_ListEntry);
+    }
+
+    static
+    BOOLEAN
+    _IsValidNodeType(
+        __in FxIoQueueNodeType NodeType
+        )
+    {
+        return ((NodeType > FxIoQueueNodeTypeInvalid) &&
+                (NodeType < FxIoQueueNodeTypeLast)) ? TRUE : FALSE;
+    }
+
+    __inline
+    BOOLEAN
+    IsNodeType(
+        __in FxIoQueueNodeType NodeType
+        )
+    {
+        return (NodeType == m_Type) ? TRUE : FALSE;
+    }
+};
+
+//
+// These FxIoQueue private Enum's control the internal state machine
+//
+
+// begin_wpp enum
+typedef enum FxIoQueuePowerState {
+    FxIoQueuePowerInvalid = 0,
+    FxIoQueuePowerOn,
+    FxIoQueuePowerOff,
+    FxIoQueuePowerStartingTransition,
+    FxIoQueuePowerStopping,
+    FxIoQueuePowerStoppingNotifyingDriver,
+    FxIoQueuePowerStoppingDriverNotified,
+    FxIoQueuePowerPurge,
+    FxIoQueuePowerPurgeNotifyingDriver,
+    FxIoQueuePowerPurgeDriverNotified,
+    FxIoQueuePowerRestarting,
+    FxIoQueuePowerRestartingNotifyingDriver,
+    FxIoQueuePowerRestartingDriverNotified,
+    FxIoQueuePowerLast,
+} FXIOQUEUE_POWER_STATE;
+// end_wpp
+
+typedef struct _FXIO_FORWARD_PROGRESS_CONTEXT {
+    //
+    // Total Number of Reserved requests
+    //
+    ULONG m_NumberOfReservedRequests;
+    //
+    // Callback invoked to allocate resources for reserved requests at init time
+    //
+    FxIoQueueForwardProgressAllocateResourcesReserved   m_IoReservedResourcesAllocate;
+    //
+    // Callback invoked to allocate resources for non-reserved requests at run time
+    //
+    FxIoQueueForwardProgressAllocateResources   m_IoResourcesAllocate;
+    //
+    // Callback invoked to Examine the IRP and decide whether to fail it or not
+    //
+    FxIoQueueForwardProgressExamineIrp       m_IoExamineIrp;
+    //
+    // Policy configured for forward progress
+    //
+    WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY  m_Policy;
+    //
+    // List of available reserved requests
+    //
+    LIST_ENTRY  m_ReservedRequestList;
+
+    //
+    // List of in use reserved requests
+    //
+    LIST_ENTRY  m_ReservedRequestInUseList;
+
+    //
+    // List of all pended IRPs
+    //
+    LIST_ENTRY  m_PendedIrpList;
+    //
+    // This lock is used to add new entreies to the pended IRP list
+    // or the  add the request back to the Reserved List
+    //
+    MxLockNoDynam m_PendedReserveLock;
+
+} FXIO_FORWARD_PROGRESS_CONTEXT, *PFXIO_FORWARD_PROGRESS_CONTEXT;
+
+//
+// This defines the valid arguments to the
+// SetStatus call.
+//
+typedef enum _FX_IO_QUEUE_SET_STATE {
+    FxIoQueueSetAcceptRequests     = 0x80000001,
+    FxIoQueueClearAcceptRequests   = 0x80000002,
+    FxIoQueueSetDispatchRequests   = 0x80000004,
+    FxIoQueueClearDispatchRequests = 0x80000008,
+    FxIoQueueSetShutdown           = 0x80010000,
+    FxIoQueueClearShutdown         = 0x80020000,
+} FX_IO_QUEUE_SET_STATE;
+
+
+//
+// This defines the internal queue state.
+//
+typedef enum _FX_IO_QUEUE_STATE {
+    //
+    // private == public values (low word).
+    //
+    FxIoQueueAcceptRequests     = WdfIoQueueAcceptRequests,     // 0x00000001
+    FxIoQueueDispatchRequests   = WdfIoQueueDispatchRequests,   // 0x00000002
+    FxIoQueueNoRequests         = WdfIoQueueNoRequests,         // 0x00000004
+    FxIoQueueDriverNoRequests   = WdfIoQueueDriverNoRequests,   // 0x00000008
+    FxIoQueuePnpHeld            = WdfIoQueuePnpHeld,            // 0x00000010
+    //
+    // private values only (high word).
+    //
+    // Queue is being shut down. Flag on means do not queue any request
+    // even if the accept request state is set. This flag prevents the
+    // following scenarios:
+    // (1) a race condition where a dispatch queue handler changes the
+    //     state of the queue to accept_requests while we are in the
+    //     middle of a power stopping (purge) operation (Win7 719587).
+    // (2) another thread calling Stop or Start on a queue that is in the
+    //     middle of a power stopping (purge) operation.
+    //
+    FxIoQueueShutdown           = 0x00010000
+} FX_IO_QUEUE_STATE;
+
+class FxIoQueue : public FxNonPagedObject, IFxHasCallbacks {
+
+    friend VOID GetTriageInfo(VOID);
+
+private:
+
+    //
+    // forward progress fields
+    //
+    PFXIO_FORWARD_PROGRESS_CONTEXT m_FwdProgContext;
+
+    //
+    // This is a true indicator whether the Queue is ready for forward progress
+    //
+    BOOLEAN m_SupportForwardProgress;
+
+    //
+    // Specifies that the queue has been configured
+    // with driver callbacks and presentation serialization
+    //
+    BOOLEAN             m_Configured;
+
+    //
+    // TRUE if this is a power managed queue. If TRUE, it is reported
+    // as a power managed queue, and will automatically start/resume
+    // based on power management requests.
+    //
+    // If false, the device driver has manual control on start/resume.
+    //
+    BOOLEAN             m_PowerManaged;
+
+    //
+    // This is TRUE if we have an outstanding reference to the
+    // Pnp package about having I/O in our queue.
+    //
+    volatile BOOLEAN    m_PowerReferenced;
+
+    //
+    // If TRUE, zero length read/writes are allowed to the driver.
+    // Otherwise, they are completed automatically with STATUS_SUCCESS.
+    //
+    BOOLEAN             m_AllowZeroLengthRequests;
+
+    //
+    // True if callback operations to the driver occur at
+    // PASSIVE_LEVEL. Also marked in FxObject, but this cache
+    // avoids acquiring FxObject state lock.
+    //
+    BOOLEAN             m_PassiveLevel;
+
+    //
+    // This is set before m_FinishDisposing is signalled to
+    // allow the Dispose thread to continue deletion of
+    // queue resources. Once this is set, no thread is
+    // allowed to run thru DispatchEvents.
+    //
+    volatile BOOLEAN    m_Deleted;
+
+    //
+    // This is set when the I/O package marks the queue
+    // for deleting, but the I/O queue deferrs its final
+    // dereference until all outstanding I/O's to the
+    // device driver are completed.
+    //
+    volatile BOOLEAN    m_Disposing;
+    MxEvent             m_FinishDisposing;
+
+    //
+    // Power State of the Queue
+    //
+    FXIOQUEUE_POWER_STATE m_PowerState;
+
+    //
+    // This is the type of queue, and is configured by the
+    // user at initial queue creation time.
+    //
+    WDF_IO_QUEUE_DISPATCH_TYPE m_Type;
+
+    //
+    // Maximum number of driver presented Requests on a parallel Queue
+    //
+    ULONG  m_MaxParallelQueuePresentedRequests;
+
+    //
+    // This is the current processing status of the queue.
+    //
+    FX_IO_QUEUE_STATE m_QueueState;
+
+    //
+    // The FxIoQueue tracks a request from the time it arrives by being
+    // enqueued, until it leaves by being completed, or forwarded.
+    //
+    // At any given time, a request may be in one the following five states:
+    //
+    // 1) Request is queued and cancelable
+    //
+    //    It is on the FxIrpQueue m_Queue using the LIST_ENTRY
+    //    FxRequest::m_Irp->Tail.Overlay.ListEntry
+    //
+    // 2) Request has been passed to the driver, and is not cancelable
+    //
+    //    It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY
+    //    FxRequest::m_OwnerListEntry
+    //
+    //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
+    //    FxRequest::m_InFlightListEntry
+    //
+    // 3) Request has been passed to the driver, and is cancelable
+    //
+    //    It is on the FxIrpQueue m_DriverCancelable using the LIST_ENTRY
+    //    FxRequest::m_Irp->Tail.Overlay.ListEntry
+    //
+    //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
+    //    FxRequest::m_InFlightListEntry
+    //
+    // 4) Request has been cancelled, but the driver has not been notified
+    //
+    //    It is on the LIST_ENTRY m_Cancelled using the LIST_ENTRY
+    //    FxRequest::m_OwnerListEntry
+    //
+    // 5) Request has been cancelled, driver has been notified, but has
+    //    not completed it yet
+    //
+    //    It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY
+    //    FxRequest::m_OwnerListEntry
+    //
+    //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
+    //    FxRequest::m_InFlightListEntry
+    //
+
+    //
+    // This is the Queue of current requests that have not
+    // been presented to the driver
+    //
+    FxIrpQueue          m_Queue;
+
+    //
+    // This is the list of requests that driver has accepted
+    // and is working on, but wants to be cancelable.
+    //
+    FxIrpQueue          m_DriverCancelable;
+
+    //
+    // This is a list of cancelled requests to be notified to the driver.
+    //
+    // FxListEntryQueueOwned of FxRequest is used for linkage
+    //
+    LIST_ENTRY          m_Cancelled;
+
+    //
+    // This is a list of request cancelled on queue waiting
+    // to be notified to the driver.
+    //
+    // FxListEntryQueueOwned of FxRequest is used for linkage
+    //
+    LIST_ENTRY          m_CanceledOnQueueList;
+
+    //
+    // This is a list of requests that the driver has accepted
+    // and is working on, but has not been completed.
+    //
+    // They may, or may not be cancelable.
+    //
+    // FxListEntryDriverOwned of FxRequest is used for linkage
+    //
+    LIST_ENTRY          m_DriverOwned;
+
+    //
+    // This is the list of power stop/start requests to be notified to
+    // the driver.
+    //
+    // FxListEntryDriverOwned of FxRequest is used for linkage
+    //
+    LIST_ENTRY          m_PowerNotify;
+
+    //
+    // This is the list of power stop requests in which the driver
+    // has been notified, and must be zero before power code can
+    // resume the power thread.
+    //
+    // FxListEntryDriverOwned of FxRequest is used for linkage
+    //
+    LIST_ENTRY          m_PowerDriverNotified;
+
+    //
+    // Pointer to FxPkgIo object that contains this queue.
+    // (No additional reference count)
+    //
+    FxPkgIo*            m_PkgIo;
+
+    //
+    // Weak pointer to the associated FxCxDeviceInfo struct.
+    //
+    FxCxDeviceInfo*     m_CxDeviceInfo;
+
+    //
+    // This is the count of currently executing callback
+    // handlers into the device driver.
+    //
+    // It is used to control the dispatch state to prevent stack
+    // recursions, as well as to handle notification when a queue
+    // is idle and has no callbacks outstanding.
+    //
+    volatile ULONG      m_Dispatching;
+
+    //
+    // This is set when a queue goes from empty to
+    // having requests and allows a callback to the driver
+    // when a queue is ready.
+    //
+    volatile BOOLEAN    m_TransitionFromEmpty;
+
+    //
+    // This flag is set when the we return no_more_requests from
+    // WdfRequesdtGetNextRequest but the queue actually holds one or
+    // more requests in cancellation state (their cancellation routine
+    // are already running).
+    // This flag insures that we call the ReadyNotify callback when a new
+    // request is inserted in the queue.
+    //
+    volatile BOOLEAN    m_ForceTransitionFromEmptyWhenAddingNewRequest;
+
+    //
+    // This is set when the driver starts a WdfIoQueueStopAndPurge operation.
+    // This is cleared in the following conditions:
+    //  (a) there are no more driver owned requests.
+    //  (b) driver re-enables the dispatch gate.
+    // When set any requeued requests will be automatically deleted.
+    //
+    volatile BOOLEAN    m_CancelDispatchedRequests;
+
+    BOOLEAN             m_IsDevicePowerPolicyOwner;
+
+    //
+    // This is the number of requests the driver
+    // currently is processing both cancellable and noncancellable.
+    //
+    // For serial queue dispatch mode, this is used
+    // to control when a request can be presented to the driver.
+    // This is also used to implement counted Queues to make
+    // sure the count doesn't exceed max. allowed on the
+    // parallel Queue.
+    //
+    volatile LONG       m_DriverIoCount;
+
+    //
+    // This is the number of requests that are about to be completed using two
+    // phase completion technique (to support queued-by-driver requests).
+    //
+    volatile LONG       m_TwoPhaseCompletions;
+
+    //
+    // These are the driver configured callbacks to send
+    // I/O events to the driver
+    //
+    FxIoQueueIoDefault         m_IoDefault;
+    FxIoQueueIoStop            m_IoStop;
+    FxIoQueueIoResume          m_IoResume;
+    FxIoQueueIoRead            m_IoRead;
+    FxIoQueueIoWrite           m_IoWrite;
+    FxIoQueueIoDeviceControl   m_IoDeviceControl;
+    FxIoQueueIoInternalDeviceControl m_IoInternalDeviceControl;
+    FxIoQueueIoCanceledOnQueue m_IoCanceledOnQueue;
+
+    FxCallbackLock*     m_IoCancelCallbackLockPtr;
+
+    //
+    // These are status events registered by the device driver
+    //
+    FxIoQueueIoState          m_IdleComplete;
+    WDFCONTEXT                 m_IdleCompleteContext;
+
+    FxIoQueueIoState          m_PurgeComplete;
+    WDFCONTEXT                 m_PurgeCompleteContext;
+
+    FxIoQueueIoState          m_ReadyNotify;
+    WDFCONTEXT                 m_ReadyNotifyContext;
+
+    //
+    // The following items support the callback constraints
+    // and handle locking and deferral
+    //
+    WDF_EXECUTION_LEVEL       m_ExecutionLevel;
+    WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope;
+
+    //
+    // These are the passive and dispatch level presentation locks
+    //
+    FxCallbackSpinLock  m_CallbackSpinLock;
+    FxCallbackMutexLock m_CallbackMutexLock;
+
+    //
+    // This pointer allows the proper lock to be acquired
+    // based on the configuration with a minimal of runtime
+    // checks. This is configured by ConfigureLocking()
+    //
+    FxCallbackLock*     m_CallbackLockPtr;
+    FxObject*           m_CallbackLockObjectPtr;
+
+    //
+    // The IoQueue must sometimes defer event delivery to the
+    // device driver due to interactions with current locks held,
+    // and the device driver configured callback constraints.
+    //
+    // When a deferral occurs, a DPC or FxSystemWorkItem is used
+    // to post an event to later deliver the event(s) to the device
+    // driver. Whether a DPC or WorkItem is used depends
+    // on the drivers configured execution level constraints.
+    //
+    // The IoQueue is designed to be robust in that multiple events
+    // may occur while the queued DPC or WorkItem is outstanding,
+    // and they will be properly processed without having to enqueue
+    // one for each event. Basically, they are just a signal that
+    // an IoQueue needs some attention that could result in device
+    // driver notification.
+    //
+    // KDPC is only needed in kernel mode
+    //
+
+
+
+#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
+    KDPC               m_Dpc;
+#endif
+
+    FxSystemWorkItem*  m_SystemWorkItem;
+
+    //
+    // These are true if the associated Dpc or Work Item is queued
+    //
+    BOOLEAN            m_DpcQueued;
+    BOOLEAN            m_WorkItemQueued;
+
+    //
+    // Track whether the above DPC and WorkItem needs to be requeued.
+    //
+    BOOLEAN            m_RequeueDeferredDispatcher;
+
+    // This is set when the Queue is power idle
+    MxEvent            m_PowerIdle;
+
+
+
+
+
+#if (FX_CORE_MODE==FX_CORE_USER_MODE)
+    MxEvent            m_RequestWaitEventUm;
+#endif
+
+public:
+
+    //
+    // List node to tie the queue with FxPkgIo.
+    //
+    FxIoQueueNode      m_IoPkgListNode;
+    //
+    // List entry is used by FxPkgIo to iterate list all the queues without
+    // holding a lock.
+    //
+    SINGLE_LIST_ENTRY  m_PowerSListEntry;
+
+public:
+    // Factory function
+    _Must_inspect_result_
+    static
+    NTSTATUS
+    _Create(
+        __in PFX_DRIVER_GLOBALS         DriverGlobals,
+        __in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
+        __in PWDF_IO_QUEUE_CONFIG       Config,
+        __in_opt FxDriver*              Caller,
+        __in FxPkgIo*                   PkgIo,
+        __in BOOLEAN                    InitialPowerStateOn,
+        __deref_out FxIoQueue**         Object
+        );
+
+    FxIoQueue(
+        __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+        __in FxPkgIo* PkgIo
+        );
+
+    virtual
+    ~FxIoQueue(
+       );
+
+    _Must_inspect_result_
+    NTSTATUS
+    Initialize(
+        __in PWDF_IO_QUEUE_CONFIG       pConfig,
+        __in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes,
+        __in_opt FxDriver*              Caller,
+        __in BOOLEAN                    InitialPowerStateOn
+        );
+
+    _Releases_lock_(this->m_SpinLock.m_Lock)
+    VOID
+    CancelForQueue(
+        __in FxRequest* pRequest,
+        __in __drv_restoresIRQL KIRQL PreviousIrql
+        );
+
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    VOID,
+    VerifyCancelForDriver,
+        _In_ FxRequest*
+        );
+
+    VOID
+    CancelForDriver(
+        __in FxRequest* pRequest
+        );
+
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    VOID,
+    VerifyValidateCompletedRequest,
+        _In_ FxRequest*
+        );
+
+    __inline
+    VOID
+    RequestCompletedCallback(
+        __in FxRequest* Request
+        )
+    {
+        //
+        // This is called when a FxRequest object completes based
+        // on the callback event registered by the I/O queue support
+        // routines.
+        //
+
+        KIRQL irql;
+
+#if FX_VERBOSE_TRACE
+        DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
+                            "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
+                            GetObjectHandle(),Request->GetHandle());
+#endif
+        VerifyValidateCompletedRequest(GetDriverGlobals(), Request);
+
+        Lock(&irql);
+
+        //
+        // I/O has been completed by the driver
+        //
+        RemoveFromDriverOwnedList(Request);
+
+        //
+        // Don't run the event dispatcher if we come from a Request
+        // complete callback in order to prevent stack recursion.
+        //
+        // Since some other thread (possibly this thread higher on
+        // the stack) is running the dispatcher, no events will get lost.
+        //
+        DispatchInternalEvents(irql);
+    }
+
+    __inline
+    VOID
+    PreRequestCompletedCallback(
+        __in FxRequest* Request
+        )
+    {
+        //
+        // This is called when a driver created request is about to be completed.
+        // This callback removes the FxRequest object from the internal queue linked
+        // lists.  A call to PostRequestCompletedCallback must be made after irp is
+        // completed.
+        //
+
+        KIRQL irql;
+
+#if FX_VERBOSE_TRACE
+        DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
+                            "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
+                            GetObjectHandle(),Request->GetHandle());
+#endif
+
+        VerifyValidateCompletedRequest(GetDriverGlobals(), Request);
+
+        Lock(&irql);
+
+        //
+        // I/O has been completed by the driver
+        //
+        PreRemoveFromDriverOwnedList(Request);
+
+        Unlock(irql);
+    }
+
+    __inline
+    VOID
+    PostRequestCompletedCallback(
+        __in FxRequest* Request
+        )
+    {
+        // Do not acccess Request, at this point the object may have already been
+        // deleted or reused.
+
+        //
+        // This is called when a queued-by-driver request (driver created) is
+        // completed or sent to a lower driver with 'send-and-forget' option.
+        // This callback allows the queue to schedule another request for delivery.
+        //
+
+        KIRQL irql;
+
+#if FX_VERBOSE_TRACE
+        DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
+                            "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
+                            GetObjectHandle(), FxRequest::_ToHandle(Request));
+#else
+        UNREFERENCED_PARAMETER(Request);
+#endif
+
+        Lock(&irql);
+
+        //
+        // I/O has been completed by the driver
+        //
+        PostRemoveFromDriverOwnedList();
+
+        //
+        // Don't run the event dispatcher if we come from a Request
+        // complete callback in order to prevent stack recursion.
+        //
+        // Since some other thread (possibly this thread higher on
+        // the stack) is running the dispatcher, no events will get lost.
+        //
+        DispatchInternalEvents(irql);
+    }
+
+    __inline
+    FxDriver*
+    GetDriver(VOID) {
+        return m_PkgIo->GetDriver();
+    }
+
+    __inline
+    CfxDevice*
+    GetDevice(VOID)
+    {
+        return m_Device;
+    }
+
+    __inline
+    FxPkgIo*
+    GetPackage(VOID) {
+        return m_PkgIo;
+    }
+
+    WDFQUEUE
+    __inline
+    GetHandle(
+        VOID
+        )
+    {
+        return (WDFQUEUE) GetObjectHandle();
+    }
+
+    __inline
+    BOOLEAN
+    IsPowerManaged() {
+        return m_PowerManaged;
+    }
+
+    VOID
+    StartPowerTransitionOn(
+        VOID
+        );
+
+    VOID
+    StartPowerTransitionOff(
+        VOID
+        );
+
+    VOID
+    StopProcessingForPower(
+        __in FxIoStopProcessingForPowerAction Action
+        );
+
+    VOID
+    ResumeProcessingForPower(
+        VOID
+        );
+
+    VOID
+    SetStateForShutdown(
+        VOID
+        );
+
+    VOID
+    ResetStateForRestart(
+        VOID
+        );
+
+    WDF_IO_QUEUE_STATE
+    GetState(
+        __out_opt PULONG   pQueueCount,
+        __out_opt PULONG   pDriverCount
+       );
+
+    VOID
+    SetState(
+        __in FX_IO_QUEUE_SET_STATE NewStatus
+       );
+
+
+    __inline
+    BOOLEAN
+    IsState(
+        __in WDF_IO_QUEUE_STATE State
+        )
+    {
+        ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states
+        return (((int)m_QueueState & (int) (State)) != 0);
+    }
+
+    __inline
+    BOOLEAN
+    IsState(
+        __in FX_IO_QUEUE_STATE State
+        )
+    {
+        ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states
+        return (((int)m_QueueState & (int) (State)) != 0);
+    }
+
+    // GetRequest Verifiers
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    NTSTATUS,
+    VerifyGetRequestUpdateFlags,
+        _In_ FxRequest*
+        );
+
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    VOID,
+    VerifyGetRequestRestoreFlags,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    GetRequest(
+        __in_opt  MdFileObject FileObject,
+        __in_opt  FxRequest*   TagRequest,
+        __deref_out FxRequest**  pOutRequest
+        );
+
+    // PeekRequest Verifiers
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    NTSTATUS,
+    VerifyPeekRequest,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    PeekRequest(
+        __in_opt  FxRequest*          TagRequest,
+        __in_opt  MdFileObject        FileObject,
+        __out_opt PWDF_REQUEST_PARAMETERS Parameters,
+        __deref_out FxRequest**         pOutRequest
+        );
+
+    // ForwardRequest Verifiers
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P2(
+    NTSTATUS,
+    VerifyForwardRequest,
+        _In_ FxIoQueue*,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    ForwardRequest(
+        __in FxIoQueue* pDestQueue,
+        __in FxRequest* pRequest
+       );
+
+    // QueueDriverCreatedRequest
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P2(
+    NTSTATUS,
+    VerifyQueueDriverCreatedRequest,
+        _In_    FxRequest*,
+        _Inout_ SHORT*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    QueueDriverCreatedRequest(
+        __in FxRequest* Request,
+        __in BOOLEAN    ParentQueue
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    VOID
+    ProcessAcknowledgedRequests(
+        __in FxRequest* Request,
+        __out PKIRQL PreviousIrql
+        );
+
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1(
+    NTSTATUS,
+    VerifyRequeue,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    Requeue(
+        __in FxRequest* pRequest
+       );
+
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P2(
+    NTSTATUS,
+    VerifyRequestCancelable,
+        _In_ FxRequest*,
+        _In_ BOOLEAN
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    RequestCancelable(
+        __in FxRequest* pRequest,
+        __in BOOLEAN    Cancelable,
+        __in_opt PFN_WDF_REQUEST_CANCEL  EvtRequestCancel,
+        __in BOOLEAN    FailIfIrpIsCancelled
+       );
+
+    _Must_inspect_result_
+    NTSTATUS
+    RequestCompleteEvent(
+       __in FxRequest* Request
+       );
+
+
+    _Must_inspect_result_
+    NTSTATUS
+    QueueRequest(
+        __in FxRequest* pRequest
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    QueueRequestFromForward(
+        __in FxRequest* pRequest
+        );
+
+    _Must_inspect_result_
+    BOOLEAN
+    CanThreadDispatchEventsLocked(
+        __in KIRQL PreviousIrql
+        );
+
+    _Releases_lock_(this->m_SpinLock.m_Lock)
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    BOOLEAN
+    DispatchEvents(
+        __in __drv_restoresIRQL KIRQL PreviousIrql,
+        __in_opt FxRequest* NewRequest = NULL
+        );
+
+    _Releases_lock_(this->m_SpinLock.m_Lock)
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    __inline
+    VOID
+    DispatchInternalEvents(
+        __in __drv_restoresIRQL KIRQL PreviousIrql
+        )
+    /*++
+
+        Routine Description:
+
+        Dispatch events and requests from the queue to the driver.
+
+        The IoQueue object lock must be held on entry, but this
+        routine returns to the caller with the lock released.
+
+        To avoid recursion, this routine checks to see if this or another
+        thread is already in the dispatch-event loop. If so, it
+        doesn't re-enter the dispatch-even loop.
+
+    --*/
+    {
+        if(m_Dispatching == 0) {
+            //
+            // Nobody is dispatching events so we must
+            // call the main DispatchEvents function because
+            // the caller of this function might have affected the
+            // state of the queue.
+            //
+            (VOID) DispatchEvents(PreviousIrql);
+
+        } else {
+
+            Unlock(PreviousIrql);
+        }
+    }
+
+
+    VOID
+    DispatchRequestToDriver(
+        __in FxRequest* pRequest
+        );
+
+    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;
+    }
+
+    _Must_inspect_result_
+    virtual
+    NTSTATUS
+    QueryInterface(
+        __in FxQueryInterfaceParams* Params
+        )
+    {
+        switch (Params->Type) {
+        case FX_TYPE_QUEUE:
+            *Params->Object = (FxIoQueue*) this;
+            break;
+
+        case FX_TYPE_IHASCALLBACKS:
+            *Params->Object = (IFxHasCallbacks*) this;
+            break;
+
+        default:
+            return __super::QueryInterface(Params);
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    virtual
+    BOOLEAN
+    Dispose(
+        VOID
+        );
+
+    //
+    // Start the Queue
+    //
+    VOID
+    QueueStart(
+        VOID
+        );
+
+    //
+    // Idle/Stop the Queue
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    QueueIdle(
+        __in BOOLEAN                    CancelQueueRequests,
+        __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,
+        __in_opt WDFCONTEXT             Context
+        );
+
+    //
+    // Idle the Queue
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    QueueIdleSynchronously(
+        __in BOOLEAN    CancelRequests
+        );
+
+    //
+    // Purge the Queue
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    QueuePurge(
+        __in BOOLEAN                 CancelQueueRequests,
+        __in BOOLEAN                 CancelDriverRequests,
+        __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,
+        __in_opt WDFCONTEXT              Context
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    QueuePurgeSynchronously(
+        VOID
+        );
+
+    //
+    // Idle the Queue
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    QueueDrain(
+        __in_opt PFN_WDF_IO_QUEUE_STATE DrainComplete,
+        __in_opt WDFCONTEXT              Context
+        );
+
+    //
+    // Idle the Queue
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    QueueDrainSynchronously(
+        VOID
+        );
+
+    //
+    // Notify the driver through a callback when the queue transitions
+    // from no requests to having a request.
+    //
+    _Must_inspect_result_
+    NTSTATUS
+    ReadyNotify(
+        __in PFN_WDF_IO_QUEUE_STATE QueueReady,
+        __in_opt WDFCONTEXT              Context
+        );
+
+
+    VOID
+    FlushByFileObject(
+        __in MdFileObject FileObject
+        );
+
+    //
+    // Return count of queued and driver pending requests.
+    //
+    VOID
+    GetRequestCount(
+        __out_opt PULONG pQueuedRequests,
+        __out_opt PULONG pDriverPendingRequests
+        );
+
+
+    _Must_inspect_result_
+    NTSTATUS
+    ConfigureConstraints(
+        __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes,
+        __in_opt FxDriver*              Caller
+        );
+
+    VOID
+    DeferredDispatchRequestsFromDpc(
+        VOID
+        );
+
+    VOID
+    DeferredDispatchRequestsFromWorkerThread(
+        VOID
+        );
+
+    __inline
+    static
+    FxIoQueue*
+    _FromIoPkgListEntry(
+        __in PLIST_ENTRY Entry
+        )
+    {
+        return CONTAINING_RECORD(Entry, FxIoQueue, m_IoPkgListNode.m_ListEntry);
+    }
+
+    __inline
+    static
+    FxIoQueue*
+    _FromPowerSListEntry(
+        __in PSINGLE_LIST_ENTRY Entry
+        )
+    {
+        return CONTAINING_RECORD(Entry, FxIoQueue, m_PowerSListEntry);
+    }
+
+    __declspec(noreturn)
+    VOID
+    FatalError(
+        __in NTSTATUS Status
+        );
+
+    BOOLEAN
+    IsIoEventHandlerRegistered(
+        __in WDF_REQUEST_TYPE RequestType
+        );
+
+    __inline
+    VOID
+    SetPowerState(
+        __in FXIOQUEUE_POWER_STATE PowerState
+        )
+    {
+        if (m_PowerManaged) {
+            m_PowerState = PowerState;
+        }
+    }
+
+    _Must_inspect_result_
+    NTSTATUS
+    GetReservedRequest(
+        __in MdIrp Irp,
+        __deref_out_opt FxRequest **ReservedRequest
+        );
+
+    __inline
+    BOOLEAN
+    IsForwardProgressQueue(
+        VOID
+        )
+    {
+        return m_SupportForwardProgress;
+    }
+
+    __inline
+    NTSTATUS
+    InvokeAllocateResourcesCallback(
+    __in FxRequest *Request
+    )
+    /*++
+
+    Routine Description:
+        Give callback to allocate resources at runtime for a general request
+        (not a reserved request).
+
+    --*/
+    {
+        NTSTATUS status;
+
+        ASSERT(Request->IsReserved() == FALSE);
+
+        status = STATUS_SUCCESS;
+        if (m_FwdProgContext->m_IoResourcesAllocate.Method != NULL) {
+            Request->SetPresented();
+            status = m_FwdProgContext->m_IoResourcesAllocate.Invoke(
+                GetHandle(), Request->GetHandle());
+        }
+
+        return status;
+    }
+
+    VOID
+    ReturnReservedRequest(
+        __in FxRequest *ReservedRequest
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    AllocateReservedRequest(
+        __deref_out FxRequest** Request
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    AssignForwardProgressPolicy(
+        __in PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Policy
+    );
+
+    // ForwardRequestWorker verifiers
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P1_EX(
+    ,
+    SHORT,
+    0,
+    VerifyForwardRequestUpdateFlags,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    ForwardRequestWorker(
+        __in FxRequest* Request,
+        __in FxIoQueue* DestQueue
+        );
+
+    // ForwardRequestToParent Verifiers
+    // Do not specify argument names
+    FX_DECLARE_VF_FUNCTION_P2(
+    NTSTATUS,
+    VerifyForwardRequestToParent,
+        _In_ FxIoQueue*,
+        _In_ FxRequest*
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    ForwardRequestToParent(
+        __in FxIoQueue* DestQueue,
+        __in FxRequest* Request,
+        __in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions
+        );
+
+    __inline
+    VOID
+    SetCxDeviceInfo(
+        __in FxCxDeviceInfo* CxDeviceInfo
+        )
+    {
+        m_CxDeviceInfo = CxDeviceInfo;
+    }
+
+    __inline
+    FxCxDeviceInfo*
+    GetCxDeviceInfo(
+        VOID
+        )
+    {
+        return m_CxDeviceInfo;
+    }
+
+    __inline
+    VOID
+    SetInterruptQueue(
+        VOID
+        )
+    {
+        MarkNoDeleteDDI(ObjectLock);
+    }
+
+    VOID
+    FlushQueuedDpcs(
+        VOID
+        );
+
+    VOID
+    InsertQueueDpc(
+        VOID
+    );
+
+private:
+
+    //
+    // Helper functions for event processing loop DispatchEvents()
+    //
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    VOID
+    ProcessIdleComplete(
+        __out PKIRQL PreviousIrql
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    VOID
+    ProcessPurgeComplete(
+        __out PKIRQL PreviousIrql
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    VOID
+    ProcessReadyNotify(
+        __out PKIRQL PreviousIrql
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    BOOLEAN
+    ProcessCancelledRequests(
+        __out PKIRQL PreviousIrql
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    BOOLEAN
+    ProcessCancelledRequestsOnQueue(
+        __out PKIRQL PreviousIrql
+        );
+
+    __drv_requiresIRQL(DISPATCH_LEVEL)
+    BOOLEAN
+    ProcessPowerEvents(
+        __out PKIRQL PreviousIrql
+        );
+
+    __inline
+    BOOLEAN
+    IsPowerStateNotifyingDriver(
+        VOID
+        )
+    {
+        if (m_PowerState == FxIoQueuePowerStoppingNotifyingDriver ||
+            m_PowerState == FxIoQueuePowerPurgeNotifyingDriver ||
+            m_PowerState == FxIoQueuePowerRestartingNotifyingDriver) {
+            return TRUE;
+        }
+        else {
+            return FALSE;
+        }
+    }
+
+    //
+    // Insert in the list of requests that the driver is operating
+    // on.
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    __inline
+    VOID
+    InsertInDriverOwnedList(
+        __in FxRequest* Request
+        )
+    {
+        m_DriverIoCount++;
+
+        InsertTailList(&m_DriverOwned, Request->GetListEntry(FxListEntryDriverOwned));
+        return;
+    }
+
+    //
+    // Remove the request from the list that the driver is operating
+    // on.
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    // Note: ForwardRequest and two phase completions (queued-by-driver) cases breaks
+    //          this up and manipulates the list entry and m_DriverIoCount separately.
+    //
+    __inline
+    VOID
+    RemoveFromDriverOwnedList(
+        __in FxRequest* Request
+        )
+    {
+        PLIST_ENTRY listEntry;
+
+        listEntry = Request->GetListEntry(FxListEntryDriverOwned);
+
+        RemoveEntryList(listEntry);
+        InitializeListHead(listEntry);
+
+        m_DriverIoCount--;
+        ASSERT(m_DriverIoCount >= 0);
+
+        return;
+    }
+
+    //
+    // Pre-Remove the request from the list that the driver is operating on
+    // (the first of two phase completion).
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    __inline
+    VOID
+    PreRemoveFromDriverOwnedList(
+        __in FxRequest* Request
+        )
+    {
+        PLIST_ENTRY listEntry;
+
+        listEntry = Request->GetListEntry(FxListEntryDriverOwned);
+
+        RemoveEntryList(listEntry);
+        InitializeListHead(listEntry);
+
+        m_TwoPhaseCompletions++;
+        ASSERT(m_TwoPhaseCompletions > 0);
+
+        return;
+    }
+
+    //
+    // Post-Remove the request from the list that the driver is operating on
+    // (the second of two phase completion).
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    __inline
+    VOID
+    PostRemoveFromDriverOwnedList(
+        VOID
+        )
+    {
+        m_TwoPhaseCompletions--;
+        ASSERT(m_TwoPhaseCompletions >= 0);
+
+        m_DriverIoCount--;
+        ASSERT(m_DriverIoCount >= 0);
+        return;
+    }
+
+    //
+    // This is called after inserting a new request in the IRP queue.
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    __inline
+    VOID
+    CheckTransitionFromEmpty(
+        VOID
+        )
+    {
+        if (m_Queue.GetRequestCount() == 1L ||
+            m_ForceTransitionFromEmptyWhenAddingNewRequest) {
+
+            SetTransitionFromEmpty();
+        }
+    }
+
+    //
+    // Indicate that the queue went from empty to having one or more requests.
+    //
+    // Must be called with the FxIoQueue lock held.
+    //
+    __inline
+    VOID
+    SetTransitionFromEmpty(
+        VOID
+        )
+    {
+        m_TransitionFromEmpty = TRUE;
+        m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE;
+
+        if(m_IsDevicePowerPolicyOwner &&
+           m_PowerManaged &&
+           m_PowerReferenced == FALSE) {
+
+            if (NT_SUCCESS(m_Device->m_PkgPnp->PowerReference(FALSE))) {
+                m_PowerReferenced = TRUE;
+            }
+        }
+    }
+
+    NTSTATUS
+    InsertNewRequestLocked(
+        __deref_in FxRequest** Request,
+        __in KIRQL PreviousIrql
+        );
+
+    __inline
+    NTSTATUS
+    InsertNewRequest(
+        __in FxRequest** Request,
+        __in KIRQL PreviousIrql
+        )
+    {
+        NTSTATUS status;
+
+        if (*Request != NULL) {
+            status = InsertNewRequestLocked(Request, PreviousIrql);
+        }
+        else {
+            status = STATUS_SUCCESS; // nothing to do.
+        }
+
+        return status;
+    }
+
+    VOID
+    FreeAllReservedRequests(
+        __in BOOLEAN Verify
+        );
+
+    _Must_inspect_result_
+    NTSTATUS
+    QueueForwardProgressIrpLocked(
+        __in MdIrp Irp
+        );
+
+    _Must_inspect_result_
+    MdIrp
+    GetForwardProgressIrpLocked(
+        __in_opt PFILE_OBJECT FileObject
+        );
+
+    BOOLEAN
+    IsPagingIo(
+        __in MdIrp Irp
+    );
+
+    VOID
+    PutBackReservedRequest(
+        __in FxRequest *ReservedRequest
+    )
+    {
+        KIRQL      oldIrql;
+    PLIST_ENTRY listEntry;
+
+    ASSERT(m_Deleted == FALSE);
+
+    listEntry = ReservedRequest->GetListEntry(FxListEntryForwardProgress);
+
+    m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql);
+
+    RemoveEntryList(listEntry);
+    InitializeListHead(listEntry);
+
+    InsertTailList(&m_FwdProgContext->m_ReservedRequestList, listEntry);
+
+    if (GetDriverGlobals()->FxVerifierIO) {
+      VerifierVerifyFwdProgListsLocked();
+    }
+
+    m_FwdProgContext->m_PendedReserveLock.Release(oldIrql);
+    }
+
+
+    VOID
+    GetForwardProgressIrps(
+        __in     PLIST_ENTRY    IrpListHead,
+        __in_opt MdFileObject   FileObject
+        );
+
+    VOID
+    CancelIrps(
+        __in PLIST_ENTRY    IrpListHead
+        );
+
+    VOID
+    PurgeForwardProgressIrps(
+        __in_opt MdFileObject FileObject
+        );
+
+    VOID
+    VerifierVerifyFwdProgListsLocked(
+        VOID
+        );
+
+protected:
+    static
+    EVT_IRP_QUEUE_CANCEL
+    _IrpCancelForQueue;
+
+    //
+    // This is our Cancel Safe Queue Callback from
+    // FxIrpQueue notifying us of an I/O cancellation
+    // on a driver owned request (driver queue)
+    //
+    static
+    EVT_IRP_QUEUE_CANCEL
+    _IrpCancelForDriver;
+
+    static
+    EVT_SYSTEMWORKITEM
+    _DeferredDispatchThreadThunk;
+
+    static
+    MdDeferredRoutineType
+    _DeferredDispatchDpcThunk;
+
+    static
+    EVT_WDF_IO_QUEUE_STATE
+    _PurgeComplete;
+
+    static
+    EVT_WDF_IO_QUEUE_STATE
+    _IdleComplete;
+
+    static
+    MdCancelRoutineType
+    _WdmCancelRoutineForReservedIrp;
+
+};
+
+#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
+#include "FxIoQueueKm.hpp"
+#else
+#include "FxIoQueueUm.hpp"
+#endif
+
+
+#endif // _FXIOQUEUE_H_