18a978a17SVictor Perevertkin /*++
28a978a17SVictor Perevertkin 
38a978a17SVictor Perevertkin Copyright (c) Microsoft Corporation
48a978a17SVictor Perevertkin 
58a978a17SVictor Perevertkin Module Name:
68a978a17SVictor Perevertkin 
78a978a17SVictor Perevertkin     FxIoQueue.cpp
88a978a17SVictor Perevertkin 
98a978a17SVictor Perevertkin Abstract:
108a978a17SVictor Perevertkin 
118a978a17SVictor Perevertkin     This module implements the FxIoQueue object and C interfaces
128a978a17SVictor Perevertkin 
138a978a17SVictor Perevertkin Author:
148a978a17SVictor Perevertkin 
158a978a17SVictor Perevertkin 
168a978a17SVictor Perevertkin 
178a978a17SVictor Perevertkin 
188a978a17SVictor Perevertkin Revision History:
198a978a17SVictor Perevertkin 
208a978a17SVictor Perevertkin 
218a978a17SVictor Perevertkin 
228a978a17SVictor Perevertkin 
238a978a17SVictor Perevertkin --*/
248a978a17SVictor Perevertkin 
258a978a17SVictor Perevertkin #include "ioprivshared.hpp"
26*1f377076SVictor Perevertkin #include "fxioqueue.hpp"
278a978a17SVictor Perevertkin 
288a978a17SVictor Perevertkin extern "C" {
298a978a17SVictor Perevertkin #if defined(EVENT_TRACING)
308a978a17SVictor Perevertkin #include "FxIoQueue.tmh"
318a978a17SVictor Perevertkin #endif
328a978a17SVictor Perevertkin }
338a978a17SVictor Perevertkin 
348a978a17SVictor Perevertkin //
358a978a17SVictor Perevertkin // Public constructors
368a978a17SVictor Perevertkin //
FxIoQueue(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxPkgIo * PkgIo)378a978a17SVictor Perevertkin FxIoQueue::FxIoQueue(
388a978a17SVictor Perevertkin     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
398a978a17SVictor Perevertkin     __in FxPkgIo*  PkgIo
408a978a17SVictor Perevertkin     ) :
418a978a17SVictor Perevertkin     FxNonPagedObject(FX_TYPE_QUEUE, sizeof(FxIoQueue), FxDriverGlobals),
428a978a17SVictor Perevertkin     m_CallbackSpinLock(FxDriverGlobals),
438a978a17SVictor Perevertkin     m_CallbackMutexLock(FxDriverGlobals),
448a978a17SVictor Perevertkin     m_IoPkgListNode(FxIoQueueNodeTypeQueue)
458a978a17SVictor Perevertkin  {
468a978a17SVictor Perevertkin     m_Configured = FALSE;
478a978a17SVictor Perevertkin     m_Disposing = FALSE;
488a978a17SVictor Perevertkin     m_PowerManaged = FALSE;
498a978a17SVictor Perevertkin     m_PowerState = FxIoQueuePowerOn;
508a978a17SVictor Perevertkin     m_PowerReferenced = FALSE;
518a978a17SVictor Perevertkin     m_AllowZeroLengthRequests = FALSE;
528a978a17SVictor Perevertkin     m_IsDevicePowerPolicyOwner = FALSE;
538a978a17SVictor Perevertkin     m_Type = WdfIoQueueDispatchSequential;
548a978a17SVictor Perevertkin 
558a978a17SVictor Perevertkin     // A newly created queue can not accept requests until initialized
568a978a17SVictor Perevertkin     m_QueueState = (FX_IO_QUEUE_STATE)0;
578a978a17SVictor Perevertkin 
588a978a17SVictor Perevertkin     //
598a978a17SVictor Perevertkin     // Set our Cancel callbacks
608a978a17SVictor Perevertkin     //
618a978a17SVictor Perevertkin     m_Queue.Initialize(this, _IrpCancelForQueue);
628a978a17SVictor Perevertkin 
638a978a17SVictor Perevertkin     m_DriverCancelable.Initialize(this, _IrpCancelForDriver);
648a978a17SVictor Perevertkin 
658a978a17SVictor Perevertkin     InitializeListHead(&m_Cancelled);
668a978a17SVictor Perevertkin 
678a978a17SVictor Perevertkin     InitializeListHead(&m_CanceledOnQueueList);
688a978a17SVictor Perevertkin 
698a978a17SVictor Perevertkin     InitializeListHead(&m_DriverOwned);
708a978a17SVictor Perevertkin 
718a978a17SVictor Perevertkin     InitializeListHead(&m_PowerNotify);
728a978a17SVictor Perevertkin 
738a978a17SVictor Perevertkin     InitializeListHead(&m_PowerDriverNotified);
748a978a17SVictor Perevertkin 
758a978a17SVictor Perevertkin     m_PowerSListEntry.Next = NULL;
768a978a17SVictor Perevertkin 
778a978a17SVictor Perevertkin     //
788a978a17SVictor Perevertkin     // We do not reference count the I/O package instance
798a978a17SVictor Perevertkin     // since it contains us. The fact we exist, the I/O
808a978a17SVictor Perevertkin     // package instance exists.
818a978a17SVictor Perevertkin     //
828a978a17SVictor Perevertkin     m_PkgIo = PkgIo;
838a978a17SVictor Perevertkin     m_CxDeviceInfo = NULL;
848a978a17SVictor Perevertkin 
858a978a17SVictor Perevertkin     m_Device = PkgIo->GetDevice();
868a978a17SVictor Perevertkin 
878a978a17SVictor Perevertkin     m_IsDevicePowerPolicyOwner = (m_Device->IsPnp() &&
888a978a17SVictor Perevertkin                                   m_Device->m_PkgPnp->IsPowerPolicyOwner());
898a978a17SVictor Perevertkin 
908a978a17SVictor Perevertkin     m_Dispatching = 0L;
918a978a17SVictor Perevertkin 
928a978a17SVictor Perevertkin     m_TransitionFromEmpty = FALSE;
938a978a17SVictor Perevertkin     m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE;
948a978a17SVictor Perevertkin 
958a978a17SVictor Perevertkin     m_DriverIoCount = 0L;
968a978a17SVictor Perevertkin     m_TwoPhaseCompletions = 0L;
978a978a17SVictor Perevertkin 
988a978a17SVictor Perevertkin     m_SystemWorkItem = NULL;
998a978a17SVictor Perevertkin 
1008a978a17SVictor Perevertkin     m_IdleComplete.Method = NULL;
1018a978a17SVictor Perevertkin     m_IdleCompleteContext = NULL;
1028a978a17SVictor Perevertkin 
1038a978a17SVictor Perevertkin     m_PurgeComplete.Method = NULL;
1048a978a17SVictor Perevertkin     m_PurgeCompleteContext = NULL;
1058a978a17SVictor Perevertkin 
1068a978a17SVictor Perevertkin     m_ReadyNotify.Method   = NULL;
1078a978a17SVictor Perevertkin     m_ReadyNotifyContext   = NULL;
1088a978a17SVictor Perevertkin 
1098a978a17SVictor Perevertkin     m_CallbackLockPtr      = NULL;
1108a978a17SVictor Perevertkin     m_CallbackLockObjectPtr = NULL;
1118a978a17SVictor Perevertkin 
1128a978a17SVictor Perevertkin #if FX_IS_KERNEL_MODE
1138a978a17SVictor Perevertkin 
1148a978a17SVictor Perevertkin     // Initialize the DPC used for deferrals
1158a978a17SVictor Perevertkin     KeInitializeDpc(
1168a978a17SVictor Perevertkin         &m_Dpc,
1178a978a17SVictor Perevertkin         _DeferredDispatchDpcThunk,
1188a978a17SVictor Perevertkin         this
1198a978a17SVictor Perevertkin         );
1208a978a17SVictor Perevertkin #endif
1218a978a17SVictor Perevertkin 
1228a978a17SVictor Perevertkin     m_DpcQueued = FALSE;
1238a978a17SVictor Perevertkin 
1248a978a17SVictor Perevertkin     m_WorkItemQueued = FALSE;
1258a978a17SVictor Perevertkin 
1268a978a17SVictor Perevertkin     m_RequeueDeferredDispatcher = FALSE;
1278a978a17SVictor Perevertkin 
1288a978a17SVictor Perevertkin     m_Deleted = FALSE;
1298a978a17SVictor Perevertkin     m_SupportForwardProgress = FALSE;
1308a978a17SVictor Perevertkin     m_PassiveLevel = FALSE;
1318a978a17SVictor Perevertkin 
1328a978a17SVictor Perevertkin     m_ExecutionLevel = WdfExecutionLevelInheritFromParent;
1338a978a17SVictor Perevertkin     m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
1348a978a17SVictor Perevertkin 
1358a978a17SVictor Perevertkin     m_FwdProgContext = NULL;
1368a978a17SVictor Perevertkin     MarkPassiveDispose(ObjectDoNotLock);
1378a978a17SVictor Perevertkin     m_MaxParallelQueuePresentedRequests = (ULONG)-1;
1388a978a17SVictor Perevertkin 
1398a978a17SVictor Perevertkin     return;
1408a978a17SVictor Perevertkin }
1418a978a17SVictor Perevertkin 
~FxIoQueue()1428a978a17SVictor Perevertkin FxIoQueue::~FxIoQueue()
1438a978a17SVictor Perevertkin {
1448a978a17SVictor Perevertkin     ASSERT(m_SystemWorkItem == NULL);
1458a978a17SVictor Perevertkin 
1468a978a17SVictor Perevertkin     if (m_PkgIo != NULL) {
1478a978a17SVictor Perevertkin         m_PkgIo = NULL;
1488a978a17SVictor Perevertkin     }
1498a978a17SVictor Perevertkin 
1508a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&m_Cancelled));
1518a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&m_CanceledOnQueueList));
1528a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&m_DriverOwned));
1538a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&m_PowerNotify));
1548a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&m_PowerDriverNotified));
1558a978a17SVictor Perevertkin     ASSERT(!m_PowerReferenced);
1568a978a17SVictor Perevertkin     ASSERT(!m_DpcQueued);
1578a978a17SVictor Perevertkin     ASSERT(!m_WorkItemQueued);
1588a978a17SVictor Perevertkin     ASSERT(!m_RequeueDeferredDispatcher);
1598a978a17SVictor Perevertkin     ASSERT(m_TwoPhaseCompletions == 0);
1608a978a17SVictor Perevertkin }
1618a978a17SVictor Perevertkin 
1628a978a17SVictor Perevertkin _Must_inspect_result_
1638a978a17SVictor Perevertkin 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)1648a978a17SVictor Perevertkin FxIoQueue::_Create(
1658a978a17SVictor Perevertkin     __in PFX_DRIVER_GLOBALS         DriverGlobals,
1668a978a17SVictor Perevertkin     __in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
1678a978a17SVictor Perevertkin     __in PWDF_IO_QUEUE_CONFIG       Config,
1688a978a17SVictor Perevertkin     __in_opt FxDriver*              Caller,
1698a978a17SVictor Perevertkin     __in FxPkgIo*                   PkgIo,
1708a978a17SVictor Perevertkin     __in BOOLEAN                    InitialPowerStateOn,
1718a978a17SVictor Perevertkin     __deref_out FxIoQueue**         Object
1728a978a17SVictor Perevertkin     )
1738a978a17SVictor Perevertkin {
1748a978a17SVictor Perevertkin     NTSTATUS status;
1758a978a17SVictor Perevertkin     FxIoQueue* pQueue;
1768a978a17SVictor Perevertkin 
1778a978a17SVictor Perevertkin     *Object = NULL;
1788a978a17SVictor Perevertkin 
1798a978a17SVictor Perevertkin     pQueue = new(DriverGlobals, Attributes) FxIoQueue(DriverGlobals, PkgIo);
1808a978a17SVictor Perevertkin 
1818a978a17SVictor Perevertkin     if (pQueue == NULL) {
1828a978a17SVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
1838a978a17SVictor Perevertkin         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1848a978a17SVictor Perevertkin                             "Memory allocation failed: %!STATUS!", status);
1858a978a17SVictor Perevertkin         return status;
1868a978a17SVictor Perevertkin     }
1878a978a17SVictor Perevertkin 
1888a978a17SVictor Perevertkin     //
1898a978a17SVictor Perevertkin     // Initialize it, creating the handle to pass the driver
1908a978a17SVictor Perevertkin     // and configuring its callbacks and queue type
1918a978a17SVictor Perevertkin     //
1928a978a17SVictor Perevertkin     status = pQueue->Initialize(Config,
1938a978a17SVictor Perevertkin                                 Attributes,
1948a978a17SVictor Perevertkin                                 Caller,
1958a978a17SVictor Perevertkin                                 InitialPowerStateOn);
1968a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
1978a978a17SVictor Perevertkin         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1988a978a17SVictor Perevertkin                             "Could not configure queue: %!STATUS!", status);
1998a978a17SVictor Perevertkin         goto Done;
2008a978a17SVictor Perevertkin     }
2018a978a17SVictor Perevertkin Done:
2028a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
2038a978a17SVictor Perevertkin         *Object = pQueue;
2048a978a17SVictor Perevertkin     }
2058a978a17SVictor Perevertkin     else {
2068a978a17SVictor Perevertkin         //
2078a978a17SVictor Perevertkin         // Release our newly allocated Queue object
2088a978a17SVictor Perevertkin         //
2098a978a17SVictor Perevertkin         pQueue->DeleteFromFailedCreate();
2108a978a17SVictor Perevertkin     }
2118a978a17SVictor Perevertkin 
2128a978a17SVictor Perevertkin     return status;
2138a978a17SVictor Perevertkin }
2148a978a17SVictor Perevertkin 
2158a978a17SVictor Perevertkin _Must_inspect_result_
2168a978a17SVictor Perevertkin NTSTATUS
Initialize(__in PWDF_IO_QUEUE_CONFIG pConfig,__in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes,__in_opt FxDriver * Caller,__in BOOLEAN InitialPowerStateOn)2178a978a17SVictor Perevertkin FxIoQueue::Initialize(
2188a978a17SVictor Perevertkin     __in PWDF_IO_QUEUE_CONFIG       pConfig,
2198a978a17SVictor Perevertkin     __in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes,
2208a978a17SVictor Perevertkin     __in_opt FxDriver*              Caller,
2218a978a17SVictor Perevertkin     __in BOOLEAN                    InitialPowerStateOn
2228a978a17SVictor Perevertkin     )
2238a978a17SVictor Perevertkin 
2248a978a17SVictor Perevertkin /*++
2258a978a17SVictor Perevertkin 
2268a978a17SVictor Perevertkin Routine Description:
2278a978a17SVictor Perevertkin 
2288a978a17SVictor Perevertkin     Initialize the IoQueue after creating.
2298a978a17SVictor Perevertkin 
2308a978a17SVictor Perevertkin     This creates the handle required for passing to the driver.
2318a978a17SVictor Perevertkin 
2328a978a17SVictor Perevertkin Arguments:
2338a978a17SVictor Perevertkin 
2348a978a17SVictor Perevertkin Returns:
2358a978a17SVictor Perevertkin 
2368a978a17SVictor Perevertkin     NTSTATUS
2378a978a17SVictor Perevertkin 
2388a978a17SVictor Perevertkin --*/
2398a978a17SVictor Perevertkin 
2408a978a17SVictor Perevertkin {
2418a978a17SVictor Perevertkin     NTSTATUS Status;
2428a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2438a978a17SVictor Perevertkin 
2448a978a17SVictor Perevertkin     Status = m_PowerIdle.Initialize(NotificationEvent, FALSE);
2458a978a17SVictor Perevertkin     if (!NT_SUCCESS(Status)) {
2468a978a17SVictor Perevertkin         return Status;
2478a978a17SVictor Perevertkin     }
2488a978a17SVictor Perevertkin 
2498a978a17SVictor Perevertkin     Status = m_FinishDisposing.Initialize(NotificationEvent, FALSE);
2508a978a17SVictor Perevertkin     if (!NT_SUCCESS(Status)) {
2518a978a17SVictor Perevertkin         return Status;
2528a978a17SVictor Perevertkin     }
2538a978a17SVictor Perevertkin 
2548a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_USER_MODE)
2558a978a17SVictor Perevertkin     Status = m_RequestWaitEventUm.Initialize(SynchronizationEvent, FALSE);
2568a978a17SVictor Perevertkin     if (!NT_SUCCESS(Status)) {
2578a978a17SVictor Perevertkin         return Status;
2588a978a17SVictor Perevertkin     }
2598a978a17SVictor Perevertkin #endif
2608a978a17SVictor Perevertkin 
2618a978a17SVictor Perevertkin     MarkDisposeOverride(ObjectDoNotLock);
2628a978a17SVictor Perevertkin 
2638a978a17SVictor Perevertkin     //
2648a978a17SVictor Perevertkin     // Set the execution level and callback synchronization based on
2658a978a17SVictor Perevertkin     // configuration
2668a978a17SVictor Perevertkin     //
2678a978a17SVictor Perevertkin     Status = ConfigureConstraints(QueueAttributes, Caller);
2688a978a17SVictor Perevertkin     if (!NT_SUCCESS(Status)) {
2698a978a17SVictor Perevertkin         return Status;
2708a978a17SVictor Perevertkin     }
2718a978a17SVictor Perevertkin 
2728a978a17SVictor Perevertkin     //
2738a978a17SVictor Perevertkin     // Validate dispatch type.
2748a978a17SVictor Perevertkin     //
2758a978a17SVictor Perevertkin     if (pConfig->DispatchType <= WdfIoQueueDispatchInvalid ||
2768a978a17SVictor Perevertkin         pConfig->DispatchType >= WdfIoQueueDispatchMax) {
2778a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2788a978a17SVictor Perevertkin                             "Invalid dispatch type "
2798a978a17SVictor Perevertkin                             "specified %d, Queue 0x%p %!STATUS!",
2808a978a17SVictor Perevertkin                             pConfig->DispatchType,
2818a978a17SVictor Perevertkin                             GetObjectHandle(),
2828a978a17SVictor Perevertkin                             STATUS_INVALID_PARAMETER);
2838a978a17SVictor Perevertkin         return STATUS_INVALID_PARAMETER;
2848a978a17SVictor Perevertkin     }
2858a978a17SVictor Perevertkin 
2868a978a17SVictor Perevertkin     //
2878a978a17SVictor Perevertkin     // If not a manual queue, must set at least IoStart, or one of
2888a978a17SVictor Perevertkin     // read|write|devicecontrol
2898a978a17SVictor Perevertkin     //
2908a978a17SVictor Perevertkin     if ((pConfig->DispatchType != WdfIoQueueDispatchManual) &&
2918a978a17SVictor Perevertkin         (pConfig->EvtIoDefault == NULL)) {
2928a978a17SVictor Perevertkin 
2938a978a17SVictor Perevertkin         if ((pConfig->EvtIoDefault == NULL) &&
2948a978a17SVictor Perevertkin             (pConfig->EvtIoRead == NULL) &&
2958a978a17SVictor Perevertkin             (pConfig->EvtIoWrite == NULL) &&
2968a978a17SVictor Perevertkin             (pConfig->EvtIoDeviceControl == NULL) &&
2978a978a17SVictor Perevertkin             (pConfig->EvtIoInternalDeviceControl == NULL)) {
2988a978a17SVictor Perevertkin 
2998a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
3008a978a17SVictor Perevertkin                                 "At least one of EvtIoDefault|EvtIoRead|EvtIoWrite|"
3018a978a17SVictor Perevertkin                                 "EvtIoDeviceControl|EvtIoInternalDeviceControl "
3028a978a17SVictor Perevertkin                                 "must be set %!STATUS!", STATUS_WDF_NO_CALLBACK);
3038a978a17SVictor Perevertkin             return STATUS_WDF_NO_CALLBACK;
3048a978a17SVictor Perevertkin         }
3058a978a17SVictor Perevertkin     }
3068a978a17SVictor Perevertkin 
3078a978a17SVictor Perevertkin     //
3088a978a17SVictor Perevertkin     // A manual queue should not set any callback function
3098a978a17SVictor Perevertkin     // pointers since they will not get invoked.
3108a978a17SVictor Perevertkin     //
3118a978a17SVictor Perevertkin     if (pConfig->DispatchType == WdfIoQueueDispatchManual) {
3128a978a17SVictor Perevertkin 
3138a978a17SVictor Perevertkin         if ((pConfig->EvtIoDefault != NULL) ||
3148a978a17SVictor Perevertkin             (pConfig->EvtIoRead != NULL)  ||
3158a978a17SVictor Perevertkin             (pConfig->EvtIoWrite != NULL) ||
3168a978a17SVictor Perevertkin             (pConfig->EvtIoDeviceControl != NULL) ||
3178a978a17SVictor Perevertkin             (pConfig->EvtIoInternalDeviceControl != NULL)) {
3188a978a17SVictor Perevertkin 
3198a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
3208a978a17SVictor Perevertkin                                 "Cannot set io callback events "
3218a978a17SVictor Perevertkin                                 "on a manual WDFQUEUE 0x%p %!STATUS!",
3228a978a17SVictor Perevertkin                                 GetObjectHandle(),
3238a978a17SVictor Perevertkin                                 STATUS_INVALID_PARAMETER);
3248a978a17SVictor Perevertkin             return STATUS_INVALID_PARAMETER;
3258a978a17SVictor Perevertkin         }
3268a978a17SVictor Perevertkin     }
3278a978a17SVictor Perevertkin 
3288a978a17SVictor Perevertkin     //
3298a978a17SVictor Perevertkin     // For version less than v1.9  m_MaxParallelQueuePresentedRequests is set to
3308a978a17SVictor Perevertkin     // -1 by the FxIoQueue Constructor.
3318a978a17SVictor Perevertkin     // By checking > below we mean v1.9 and above (public API already did the official
3328a978a17SVictor Perevertkin     // validation).
3338a978a17SVictor Perevertkin     //
3348a978a17SVictor Perevertkin     if (pConfig->Size > sizeof(WDF_IO_QUEUE_CONFIG_V1_7)) {
3358a978a17SVictor Perevertkin         if (pConfig->Settings.Parallel.NumberOfPresentedRequests != 0 &&
3368a978a17SVictor Perevertkin              (pConfig->DispatchType == WdfIoQueueDispatchSequential ||
3378a978a17SVictor Perevertkin                pConfig->DispatchType == WdfIoQueueDispatchManual)) {
3388a978a17SVictor Perevertkin             Status =  STATUS_INVALID_PARAMETER;
3398a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
3408a978a17SVictor Perevertkin                                 "Cannot have  NumberOfPresentedRequests other "
3418a978a17SVictor Perevertkin                                 "than 0 on a Sequential or manual WDFQUEUE 0x%p."
3428a978a17SVictor Perevertkin                                 "Make Sure you set NumberOfPresentedRequests"
3438a978a17SVictor Perevertkin                                 " to 0, %!STATUS!",
3448a978a17SVictor Perevertkin                                 GetObjectHandle(),
3458a978a17SVictor Perevertkin                                 Status
3468a978a17SVictor Perevertkin                                 );
3478a978a17SVictor Perevertkin             return Status;
3488a978a17SVictor Perevertkin 
3498a978a17SVictor Perevertkin         }
3508a978a17SVictor Perevertkin         else{
3518a978a17SVictor Perevertkin             m_MaxParallelQueuePresentedRequests =
3528a978a17SVictor Perevertkin                 pConfig->Settings.Parallel.NumberOfPresentedRequests;
3538a978a17SVictor Perevertkin         }
3548a978a17SVictor Perevertkin     }
3558a978a17SVictor Perevertkin 
3568a978a17SVictor Perevertkin     //
3578a978a17SVictor Perevertkin     // Initialize our workitem if we have to support passive callbacks
3588a978a17SVictor Perevertkin     //
3598a978a17SVictor Perevertkin     if (m_PassiveLevel) {
3608a978a17SVictor Perevertkin 
3618a978a17SVictor Perevertkin         Status = FxSystemWorkItem::_Create(FxDriverGlobals,
3628a978a17SVictor Perevertkin                                           m_Device->GetDeviceObject(),
3638a978a17SVictor Perevertkin                                           &m_SystemWorkItem
3648a978a17SVictor Perevertkin                                           );
3658a978a17SVictor Perevertkin 
3668a978a17SVictor Perevertkin         if (!NT_SUCCESS(Status)) {
3678a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
3688a978a17SVictor Perevertkin                                 "Could not allocate workitem: %!STATUS!", Status);
3698a978a17SVictor Perevertkin             return Status;
3708a978a17SVictor Perevertkin         }
3718a978a17SVictor Perevertkin     }
3728a978a17SVictor Perevertkin 
3738a978a17SVictor Perevertkin     m_Type = pConfig->DispatchType;
3748a978a17SVictor Perevertkin 
3758a978a17SVictor Perevertkin     switch(pConfig->PowerManaged) {
3768a978a17SVictor Perevertkin 
3778a978a17SVictor Perevertkin         case WdfUseDefault:
3788a978a17SVictor Perevertkin             if(m_Device->IsFilter()){
3798a978a17SVictor Perevertkin                 m_PowerManaged = FALSE;
3808a978a17SVictor Perevertkin             } else {
3818a978a17SVictor Perevertkin                 m_PowerManaged = TRUE;
3828a978a17SVictor Perevertkin             }
3838a978a17SVictor Perevertkin             break;
3848a978a17SVictor Perevertkin 
3858a978a17SVictor Perevertkin         case WdfTrue:
3868a978a17SVictor Perevertkin             m_PowerManaged = TRUE;
3878a978a17SVictor Perevertkin             break;
3888a978a17SVictor Perevertkin 
3898a978a17SVictor Perevertkin         case WdfFalse:
3908a978a17SVictor Perevertkin             m_PowerManaged = FALSE;
3918a978a17SVictor Perevertkin             break;
3928a978a17SVictor Perevertkin         default:
3938a978a17SVictor Perevertkin             ASSERTMSG("Invalid value in WDF_IO_QUEUE_CONFIG PowerManaged field\n", FALSE);
3948a978a17SVictor Perevertkin             break;
3958a978a17SVictor Perevertkin     }
3968a978a17SVictor Perevertkin 
3978a978a17SVictor Perevertkin     //
3988a978a17SVictor Perevertkin     // Queues for NonPnp devices can't be power managed.
3998a978a17SVictor Perevertkin     //
4008a978a17SVictor Perevertkin     if(m_Device->IsLegacy()) {
4018a978a17SVictor Perevertkin         m_PowerManaged = FALSE;
4028a978a17SVictor Perevertkin     }
4038a978a17SVictor Perevertkin 
4048a978a17SVictor Perevertkin     //
4058a978a17SVictor Perevertkin     // If power managed queue, ensure its initial power state
4068a978a17SVictor Perevertkin     // is same as the device.
4078a978a17SVictor Perevertkin     //
4088a978a17SVictor Perevertkin     if (m_PowerManaged) {
4098a978a17SVictor Perevertkin         if (InitialPowerStateOn) {
4108a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerOn;
4118a978a17SVictor Perevertkin         }
4128a978a17SVictor Perevertkin         else {
4138a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerOff;
4148a978a17SVictor Perevertkin         }
4158a978a17SVictor Perevertkin     } else {
4168a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerOn;
4178a978a17SVictor Perevertkin     }
4188a978a17SVictor Perevertkin 
4198a978a17SVictor Perevertkin     m_AllowZeroLengthRequests = pConfig->AllowZeroLengthRequests;
4208a978a17SVictor Perevertkin 
4218a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
4228a978a17SVictor Perevertkin                         "EvtIoDefault 0x%p, EvtIoRead 0x%p, EvtIoWrite 0x%p, "
4238a978a17SVictor Perevertkin                         "EvtIoDeviceControl 0x%p for WDFQUEUE 0x%p",
4248a978a17SVictor Perevertkin                         pConfig->EvtIoDefault,
4258a978a17SVictor Perevertkin                         pConfig->EvtIoRead,
4268a978a17SVictor Perevertkin                         pConfig->EvtIoWrite,
4278a978a17SVictor Perevertkin                         pConfig->EvtIoDeviceControl, GetObjectHandle());
4288a978a17SVictor Perevertkin 
4298a978a17SVictor Perevertkin     m_IoDefault.Method  = pConfig->EvtIoDefault;
4308a978a17SVictor Perevertkin     m_IoStop.Method   = pConfig->EvtIoStop;
4318a978a17SVictor Perevertkin     m_IoResume.Method = pConfig->EvtIoResume;
4328a978a17SVictor Perevertkin     m_IoRead.Method   = pConfig->EvtIoRead;
4338a978a17SVictor Perevertkin     m_IoWrite.Method  = pConfig->EvtIoWrite;
4348a978a17SVictor Perevertkin     m_IoDeviceControl.Method         = pConfig->EvtIoDeviceControl;
4358a978a17SVictor Perevertkin     m_IoInternalDeviceControl.Method = pConfig->EvtIoInternalDeviceControl;
4368a978a17SVictor Perevertkin     m_IoCanceledOnQueue.Method = pConfig->EvtIoCanceledOnQueue;
4378a978a17SVictor Perevertkin 
4388a978a17SVictor Perevertkin 
4398a978a17SVictor Perevertkin     // A newly created queue can accept and dispatch requests once initialized
4408a978a17SVictor Perevertkin     SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests|FxIoQueueSetDispatchRequests));
4418a978a17SVictor Perevertkin 
4428a978a17SVictor Perevertkin     m_Configured = TRUE;
4438a978a17SVictor Perevertkin 
4448a978a17SVictor Perevertkin     return STATUS_SUCCESS;
4458a978a17SVictor Perevertkin }
4468a978a17SVictor Perevertkin 
4478a978a17SVictor Perevertkin BOOLEAN
Dispose()4488a978a17SVictor Perevertkin FxIoQueue::Dispose(
4498a978a17SVictor Perevertkin     )
4508a978a17SVictor Perevertkin /*++
4518a978a17SVictor Perevertkin 
4528a978a17SVictor Perevertkin Routine Description:
4538a978a17SVictor Perevertkin 
4548a978a17SVictor Perevertkin     Should be called at PASSIVE_LEVEL because of the synchronous call
4558a978a17SVictor Perevertkin     to drain requests, workitems, and dpcs associated with this queue.
4568a978a17SVictor Perevertkin 
4578a978a17SVictor Perevertkin Arguments:
4588a978a17SVictor Perevertkin 
4598a978a17SVictor Perevertkin Returns:
4608a978a17SVictor Perevertkin 
4618a978a17SVictor Perevertkin     TRUE or FALSE
4628a978a17SVictor Perevertkin 
4638a978a17SVictor Perevertkin --*/
4648a978a17SVictor Perevertkin {
4658a978a17SVictor Perevertkin     KIRQL irql;
4668a978a17SVictor Perevertkin 
4678a978a17SVictor Perevertkin     if (IsCommitted() == FALSE)  {
4688a978a17SVictor Perevertkin         //
4698a978a17SVictor Perevertkin         // We called DeleteFromFailedCreate because we couldn't commit the
4708a978a17SVictor Perevertkin         // object.
4718a978a17SVictor Perevertkin         //
4728a978a17SVictor Perevertkin         goto End;
4738a978a17SVictor Perevertkin     }
4748a978a17SVictor Perevertkin 
4758a978a17SVictor Perevertkin     //
4768a978a17SVictor Perevertkin     // If object is commited means we are added to the FxPkgIo queue list.
4778a978a17SVictor Perevertkin     //
4788a978a17SVictor Perevertkin     //
4798a978a17SVictor Perevertkin     // Purge the queue asynchrnously without providing any callback. That way,
4808a978a17SVictor Perevertkin     // we allow the driver to have an outstanding purge request while the delete
4818a978a17SVictor Perevertkin     // is in progress.
4828a978a17SVictor Perevertkin     //
4838a978a17SVictor Perevertkin     (VOID) QueuePurge(TRUE, TRUE, NULL, NULL);
4848a978a17SVictor Perevertkin 
4858a978a17SVictor Perevertkin     Lock(&irql);
4868a978a17SVictor Perevertkin 
4878a978a17SVictor Perevertkin     //
4888a978a17SVictor Perevertkin     // Mark that this queue is disposing
4898a978a17SVictor Perevertkin     //
4908a978a17SVictor Perevertkin 
4918a978a17SVictor Perevertkin     ASSERT(m_Disposing == FALSE);
4928a978a17SVictor Perevertkin 
4938a978a17SVictor Perevertkin     m_Disposing = TRUE;
4948a978a17SVictor Perevertkin 
4958a978a17SVictor Perevertkin     //
4968a978a17SVictor Perevertkin     // Just make sure the state hasn't changed after the purge.
4978a978a17SVictor Perevertkin     //
4988a978a17SVictor Perevertkin     ASSERT(IsState(WdfIoQueueAcceptRequests) == FALSE);
4998a978a17SVictor Perevertkin 
5008a978a17SVictor Perevertkin     //
5018a978a17SVictor Perevertkin     // Call the FxPkgIo to remove its references to this queue
5028a978a17SVictor Perevertkin     //
5038a978a17SVictor Perevertkin     // Note: We are holding the queue lock to prevent races, and
5048a978a17SVictor Perevertkin     //       FxPkgIo never calls FxIoQueue methods while holding
5058a978a17SVictor Perevertkin     //       its lock.
5068a978a17SVictor Perevertkin     //
5078a978a17SVictor Perevertkin     m_PkgIo->RemoveQueueReferences(this);
5088a978a17SVictor Perevertkin 
5098a978a17SVictor Perevertkin     DispatchEvents(irql);
5108a978a17SVictor Perevertkin 
5118a978a17SVictor Perevertkin     //
5128a978a17SVictor Perevertkin     // Wait for the finished event to be signalled. This event will
5138a978a17SVictor Perevertkin     // be signalled when the queue is in a disposed state and there
5148a978a17SVictor Perevertkin     // are no more pending events.
5158a978a17SVictor Perevertkin     //
5168a978a17SVictor Perevertkin     GetDriverGlobals()->WaitForSignal(m_FinishDisposing.GetSelfPointer(),
5178a978a17SVictor Perevertkin             "waiting for the queue to be deleted, WDFQUEUE", GetHandle(),
5188a978a17SVictor Perevertkin             GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
5198a978a17SVictor Perevertkin             WaitSignalBreakUnderVerifier);
5208a978a17SVictor Perevertkin 
5218a978a17SVictor Perevertkin 
5228a978a17SVictor Perevertkin     ASSERT(m_Deleted == TRUE);
5238a978a17SVictor Perevertkin 
5248a978a17SVictor Perevertkin     ASSERT(m_Queue.GetRequestCount() == 0);
5258a978a17SVictor Perevertkin     ASSERT(m_DriverIoCount == 0);
5268a978a17SVictor Perevertkin 
5278a978a17SVictor Perevertkin     if (IsForwardProgressQueue()) {
5288a978a17SVictor Perevertkin         FreeAllReservedRequests(TRUE);
5298a978a17SVictor Perevertkin         ASSERT(IsListEmpty(&m_FwdProgContext->m_ReservedRequestList));
5308a978a17SVictor Perevertkin         ASSERT(IsListEmpty(&m_FwdProgContext->m_PendedIrpList));
5318a978a17SVictor Perevertkin     }
5328a978a17SVictor Perevertkin 
5338a978a17SVictor Perevertkin     if (m_FwdProgContext != NULL) {
5348a978a17SVictor Perevertkin         m_FwdProgContext->m_PendedReserveLock.Uninitialize();
5358a978a17SVictor Perevertkin         FxPoolFree(m_FwdProgContext);
5368a978a17SVictor Perevertkin         m_FwdProgContext = NULL;
5378a978a17SVictor Perevertkin     }
5388a978a17SVictor Perevertkin 
5398a978a17SVictor Perevertkin     //
5408a978a17SVictor Perevertkin     // Rundown the workitem.
5418a978a17SVictor Perevertkin     //
5428a978a17SVictor Perevertkin     if (m_SystemWorkItem != NULL) {
5438a978a17SVictor Perevertkin         m_SystemWorkItem->DeleteObject();
5448a978a17SVictor Perevertkin         m_SystemWorkItem = NULL;
5458a978a17SVictor Perevertkin     }
5468a978a17SVictor Perevertkin 
5478a978a17SVictor Perevertkin     //
5488a978a17SVictor Perevertkin     // Rundown the DPCs
5498a978a17SVictor Perevertkin     //
5508a978a17SVictor Perevertkin     if (m_DpcQueued) {
5518a978a17SVictor Perevertkin         FlushQueuedDpcs();
5528a978a17SVictor Perevertkin     }
5538a978a17SVictor Perevertkin 
5548a978a17SVictor Perevertkin     //
5558a978a17SVictor Perevertkin     // All callbacks into the device driver acquire and release a
5568a978a17SVictor Perevertkin     // reference on the queue. This ensures that the queue will
5578a978a17SVictor Perevertkin     // not actually complete deleting until return from any
5588a978a17SVictor Perevertkin     // outstanding event callbacks into the device driver.
5598a978a17SVictor Perevertkin     //
5608a978a17SVictor Perevertkin     // See DispatchRequestToDriver()
5618a978a17SVictor Perevertkin     //
5628a978a17SVictor Perevertkin End:
5638a978a17SVictor Perevertkin 
564*1f377076SVictor Perevertkin     FxNonPagedObject::Dispose(); // __super call
5658a978a17SVictor Perevertkin 
5668a978a17SVictor Perevertkin     return TRUE;
5678a978a17SVictor Perevertkin }
5688a978a17SVictor Perevertkin 
5698a978a17SVictor Perevertkin _Must_inspect_result_
5708a978a17SVictor Perevertkin NTSTATUS
ConfigureConstraints(__in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes,__in_opt FxDriver * Caller)5718a978a17SVictor Perevertkin FxIoQueue::ConfigureConstraints(
5728a978a17SVictor Perevertkin     __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes,
5738a978a17SVictor Perevertkin     __in_opt FxDriver*              Caller
5748a978a17SVictor Perevertkin     )
5758a978a17SVictor Perevertkin 
5768a978a17SVictor Perevertkin /*++
5778a978a17SVictor Perevertkin 
5788a978a17SVictor Perevertkin Routine Description:
5798a978a17SVictor Perevertkin 
5808a978a17SVictor Perevertkin     Configures the locking and threading model for the
5818a978a17SVictor Perevertkin     Queue according to parameters specified by the device
5828a978a17SVictor Perevertkin     driver when it initialized.
5838a978a17SVictor Perevertkin 
5848a978a17SVictor Perevertkin Arguments:
5858a978a17SVictor Perevertkin 
5868a978a17SVictor Perevertkin Returns:
5878a978a17SVictor Perevertkin 
5888a978a17SVictor Perevertkin     NTSTATUS
5898a978a17SVictor Perevertkin 
5908a978a17SVictor Perevertkin --*/
5918a978a17SVictor Perevertkin 
5928a978a17SVictor Perevertkin {
5938a978a17SVictor Perevertkin     WDF_EXECUTION_LEVEL ParentLevel;
5948a978a17SVictor Perevertkin     WDF_SYNCHRONIZATION_SCOPE ParentScope;
5958a978a17SVictor Perevertkin     BOOLEAN AutomaticLockingRequired;
5968a978a17SVictor Perevertkin 
5978a978a17SVictor Perevertkin     AutomaticLockingRequired = FALSE;
5988a978a17SVictor Perevertkin     ASSERT(m_Device != NULL);
5998a978a17SVictor Perevertkin 
6008a978a17SVictor Perevertkin     //
6018a978a17SVictor Perevertkin     // Initialize both spin and mutex locks
6028a978a17SVictor Perevertkin     //
6038a978a17SVictor Perevertkin     m_CallbackSpinLock.Initialize(this);
6048a978a17SVictor Perevertkin     m_CallbackMutexLock.Initialize(this);
6058a978a17SVictor Perevertkin 
6068a978a17SVictor Perevertkin     //
6078a978a17SVictor Perevertkin     // If WDF_OBJECT_ATTRIBUTES is specified, these override any
6088a978a17SVictor Perevertkin     // default settings.
6098a978a17SVictor Perevertkin     //
6108a978a17SVictor Perevertkin     if (ObjectAttributes != NULL) {
6118a978a17SVictor Perevertkin         m_ExecutionLevel = ObjectAttributes->ExecutionLevel;
6128a978a17SVictor Perevertkin         m_SynchronizationScope = ObjectAttributes->SynchronizationScope;
6138a978a17SVictor Perevertkin     }
6148a978a17SVictor Perevertkin 
6158a978a17SVictor Perevertkin     //
6168a978a17SVictor Perevertkin     // If no WDFQUEUE specific attributes are specified, we
6178a978a17SVictor Perevertkin     // get them from WDFDEVICE, which allows WDFDEVICE to
6188a978a17SVictor Perevertkin     // provide a default for all WDFQUEUE's created.
6198a978a17SVictor Perevertkin     //
6208a978a17SVictor Perevertkin     m_Device->GetConstraints(&ParentLevel, &ParentScope);
6218a978a17SVictor Perevertkin     ASSERT(ParentLevel != WdfExecutionLevelInheritFromParent);
6228a978a17SVictor Perevertkin     ASSERT(ParentScope != WdfSynchronizationScopeInheritFromParent);
6238a978a17SVictor Perevertkin 
6248a978a17SVictor Perevertkin     if (m_ExecutionLevel == WdfExecutionLevelInheritFromParent) {
6258a978a17SVictor Perevertkin         m_ExecutionLevel = ParentLevel;
6268a978a17SVictor Perevertkin     }
6278a978a17SVictor Perevertkin 
6288a978a17SVictor Perevertkin     if (m_SynchronizationScope == WdfSynchronizationScopeInheritFromParent) {
6298a978a17SVictor Perevertkin         m_SynchronizationScope = ParentScope;
6308a978a17SVictor Perevertkin     }
6318a978a17SVictor Perevertkin 
6328a978a17SVictor Perevertkin     //
6338a978a17SVictor Perevertkin     // For backward compatibility purposes always have a lock associated with the
6348a978a17SVictor Perevertkin     // object even for WdfSynchronizationScopeNone.  This is so that we return a non-null
6358a978a17SVictor Perevertkin     // presentation lock for the WDFQUEUE object.
6368a978a17SVictor Perevertkin     //
6378a978a17SVictor Perevertkin     if (m_ExecutionLevel == WdfExecutionLevelPassive) {
6388a978a17SVictor Perevertkin         //
6398a978a17SVictor Perevertkin         // Mark FxObject as passive level to ensure that Dispose and Destroy
6408a978a17SVictor Perevertkin         // callbacks are passive to the driver
6418a978a17SVictor Perevertkin         //
6428a978a17SVictor Perevertkin         MarkPassiveCallbacks(ObjectDoNotLock);
6438a978a17SVictor Perevertkin         m_PassiveLevel = TRUE;
6448a978a17SVictor Perevertkin 
6458a978a17SVictor Perevertkin         //
6468a978a17SVictor Perevertkin         // Passive Callbacks constraint has been set, we use a mutex for the
6478a978a17SVictor Perevertkin         // callback lock.
6488a978a17SVictor Perevertkin         //
6498a978a17SVictor Perevertkin         m_CallbackLockPtr = &m_CallbackMutexLock;
6508a978a17SVictor Perevertkin         m_CallbackLockObjectPtr = this;
6518a978a17SVictor Perevertkin     }
6528a978a17SVictor Perevertkin     else {
6538a978a17SVictor Perevertkin         //
6548a978a17SVictor Perevertkin         // If no passive level constraint is specified, then spinlocks
6558a978a17SVictor Perevertkin         // are used for callbacks since they are lightweight and work with
6568a978a17SVictor Perevertkin         // DPC's and Timer's
6578a978a17SVictor Perevertkin         //
6588a978a17SVictor Perevertkin         m_CallbackLockPtr = &m_CallbackSpinLock;
6598a978a17SVictor Perevertkin         m_CallbackLockObjectPtr = this;
6608a978a17SVictor Perevertkin     }
6618a978a17SVictor Perevertkin 
6628a978a17SVictor Perevertkin     //
6638a978a17SVictor Perevertkin     // Configure synchronization scope
6648a978a17SVictor Perevertkin     //
6658a978a17SVictor Perevertkin     if (m_SynchronizationScope == WdfSynchronizationScopeDevice) {
6668a978a17SVictor Perevertkin         NTSTATUS status;
6678a978a17SVictor Perevertkin 
6688a978a17SVictor Perevertkin         //
6698a978a17SVictor Perevertkin         // WDF extensions are not allowed to use this type of synchronization.
6708a978a17SVictor Perevertkin         //
6718a978a17SVictor Perevertkin         if (Caller != NULL &&  Caller != GetDriverGlobals()->Driver) {
6728a978a17SVictor Perevertkin             status = STATUS_INVALID_PARAMETER;
6738a978a17SVictor Perevertkin             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
6748a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p Synchronization scope is set to "
6758a978a17SVictor Perevertkin                             "device; WDF extension drivers are not allowed "
6768a978a17SVictor Perevertkin                             "to use this type of synchronization, %!STATUS!",
6778a978a17SVictor Perevertkin                             GetObjectHandle(), status);
6788a978a17SVictor Perevertkin             return status;
6798a978a17SVictor Perevertkin         }
6808a978a17SVictor Perevertkin 
6818a978a17SVictor Perevertkin         //
6828a978a17SVictor Perevertkin         // If we inherit the Sync. scope from parent or device
6838a978a17SVictor Perevertkin         // and if the parent/device has Exec. Level different  from Queue
6848a978a17SVictor Perevertkin         // then disallow that case.
6858a978a17SVictor Perevertkin         // FUTURE PROOF NOTE: Adding a new Execution Level will need reevaluation
6868a978a17SVictor Perevertkin         // of the check below.
6878a978a17SVictor Perevertkin         //
6888a978a17SVictor Perevertkin         if (ParentLevel != m_ExecutionLevel) {
6898a978a17SVictor Perevertkin             status = STATUS_INVALID_PARAMETER;
6908a978a17SVictor Perevertkin             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
6918a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p Synchronization scope is set to device"
6928a978a17SVictor Perevertkin                             " but the Device ExecutionLevel: 0x%x"
6938a978a17SVictor Perevertkin                             " doesn't match Queue ExecutionLevel: 0x%x, %!STATUS!",
6948a978a17SVictor Perevertkin                             GetObjectHandle(), ParentLevel,
6958a978a17SVictor Perevertkin                             m_ExecutionLevel, status);
6968a978a17SVictor Perevertkin             return status;
6978a978a17SVictor Perevertkin          }
6988a978a17SVictor Perevertkin         //
6998a978a17SVictor Perevertkin         // Per device automatic callback synchronization, so we update our
7008a978a17SVictor Perevertkin         // callback lock ptr to point to the devices lock
7018a978a17SVictor Perevertkin         //
7028a978a17SVictor Perevertkin         AutomaticLockingRequired = TRUE;
7038a978a17SVictor Perevertkin 
7048a978a17SVictor Perevertkin         //
7058a978a17SVictor Perevertkin         // Get the callback lock and object from the device
7068a978a17SVictor Perevertkin         //
7078a978a17SVictor Perevertkin         m_CallbackLockPtr = m_Device->GetCallbackLockPtr(&m_CallbackLockObjectPtr);
7088a978a17SVictor Perevertkin     }
7098a978a17SVictor Perevertkin     else if (m_SynchronizationScope == WdfSynchronizationScopeQueue) {
7108a978a17SVictor Perevertkin         //
7118a978a17SVictor Perevertkin         // Per object automatic serialization
7128a978a17SVictor Perevertkin         //
7138a978a17SVictor Perevertkin         AutomaticLockingRequired = TRUE;
7148a978a17SVictor Perevertkin 
7158a978a17SVictor Perevertkin         // m_CallbackLockPtr has been set above in execution level constraint
7168a978a17SVictor Perevertkin     }
7178a978a17SVictor Perevertkin 
7188a978a17SVictor Perevertkin 
7198a978a17SVictor Perevertkin     if (AutomaticLockingRequired) {
7208a978a17SVictor Perevertkin         //
7218a978a17SVictor Perevertkin         // If automatic locking has been configured, set the lock
7228a978a17SVictor Perevertkin         // on the FxCallback object delegates
7238a978a17SVictor Perevertkin         //
7248a978a17SVictor Perevertkin         m_IoDefault.SetCallbackLockPtr(m_CallbackLockPtr);
7258a978a17SVictor Perevertkin         m_IoStop.SetCallbackLockPtr(m_CallbackLockPtr);
7268a978a17SVictor Perevertkin         m_IoResume.SetCallbackLockPtr(m_CallbackLockPtr);
7278a978a17SVictor Perevertkin         m_IoRead.SetCallbackLockPtr(m_CallbackLockPtr);
7288a978a17SVictor Perevertkin         m_IoWrite.SetCallbackLockPtr(m_CallbackLockPtr);
7298a978a17SVictor Perevertkin         m_IoDeviceControl.SetCallbackLockPtr(m_CallbackLockPtr);
7308a978a17SVictor Perevertkin         m_IoInternalDeviceControl.SetCallbackLockPtr(m_CallbackLockPtr);
7318a978a17SVictor Perevertkin         m_PurgeComplete.SetCallbackLockPtr(m_CallbackLockPtr);
7328a978a17SVictor Perevertkin         m_ReadyNotify.SetCallbackLockPtr(m_CallbackLockPtr);
7338a978a17SVictor Perevertkin         m_IoCanceledOnQueue.SetCallbackLockPtr(m_CallbackLockPtr);
7348a978a17SVictor Perevertkin 
7358a978a17SVictor Perevertkin         m_IoCancelCallbackLockPtr = m_CallbackLockPtr;
7368a978a17SVictor Perevertkin     }
7378a978a17SVictor Perevertkin     else {
7388a978a17SVictor Perevertkin         //
7398a978a17SVictor Perevertkin         // No automatic locking specified
7408a978a17SVictor Perevertkin         //
7418a978a17SVictor Perevertkin         m_IoDefault.SetCallbackLockPtr(NULL);
7428a978a17SVictor Perevertkin         m_IoStop.SetCallbackLockPtr(NULL);
7438a978a17SVictor Perevertkin         m_IoResume.SetCallbackLockPtr(NULL);
7448a978a17SVictor Perevertkin         m_IoRead.SetCallbackLockPtr(NULL);
7458a978a17SVictor Perevertkin         m_IoWrite.SetCallbackLockPtr(NULL);
7468a978a17SVictor Perevertkin         m_IoDeviceControl.SetCallbackLockPtr(NULL);
7478a978a17SVictor Perevertkin         m_IoInternalDeviceControl.SetCallbackLockPtr(NULL);
7488a978a17SVictor Perevertkin         m_PurgeComplete.SetCallbackLockPtr(NULL);
7498a978a17SVictor Perevertkin         m_ReadyNotify.SetCallbackLockPtr(NULL);
7508a978a17SVictor Perevertkin         m_IoCanceledOnQueue.SetCallbackLockPtr(NULL);
7518a978a17SVictor Perevertkin 
7528a978a17SVictor Perevertkin         m_IoCancelCallbackLockPtr = NULL;
7538a978a17SVictor Perevertkin 
7548a978a17SVictor Perevertkin     }
7558a978a17SVictor Perevertkin 
7568a978a17SVictor Perevertkin     return STATUS_SUCCESS;
7578a978a17SVictor Perevertkin }
7588a978a17SVictor Perevertkin 
7598a978a17SVictor Perevertkin WDF_IO_QUEUE_STATE
GetState(__out_opt PULONG pQueueCount,__out_opt PULONG pDriverCount)7608a978a17SVictor Perevertkin FxIoQueue::GetState(
7618a978a17SVictor Perevertkin     __out_opt PULONG pQueueCount,
7628a978a17SVictor Perevertkin     __out_opt PULONG pDriverCount
7638a978a17SVictor Perevertkin     )
7648a978a17SVictor Perevertkin {
7658a978a17SVictor Perevertkin     int stat;
7668a978a17SVictor Perevertkin     ULONG QueueCount, DriverCount;
7678a978a17SVictor Perevertkin 
7688a978a17SVictor Perevertkin     // Get request counts
7698a978a17SVictor Perevertkin     GetRequestCount(&QueueCount, &DriverCount);
7708a978a17SVictor Perevertkin 
7718a978a17SVictor Perevertkin     if (pQueueCount ) *pQueueCount = QueueCount;
7728a978a17SVictor Perevertkin 
7738a978a17SVictor Perevertkin     if (pDriverCount ) *pDriverCount = DriverCount;
7748a978a17SVictor Perevertkin 
7758a978a17SVictor Perevertkin     //
7768a978a17SVictor Perevertkin     // First fill in the values that are kept up to date at runtime
7778a978a17SVictor Perevertkin     //
7788a978a17SVictor Perevertkin     stat = (int)m_QueueState & (int)(WdfIoQueueAcceptRequests | WdfIoQueueDispatchRequests);
7798a978a17SVictor Perevertkin 
7808a978a17SVictor Perevertkin     //
7818a978a17SVictor Perevertkin     // Set additional information bits from information retrieved
7828a978a17SVictor Perevertkin     // from other sources. It's cheaper to get this info at the infrequent
7838a978a17SVictor Perevertkin     // GetStatus time, rather than keep the bits up to date at each
7848a978a17SVictor Perevertkin     // request and queue transition.
7858a978a17SVictor Perevertkin     //
7868a978a17SVictor Perevertkin     if (QueueCount == 0) {
7878a978a17SVictor Perevertkin         stat = stat | (int)WdfIoQueueNoRequests;
7888a978a17SVictor Perevertkin     }
7898a978a17SVictor Perevertkin 
7908a978a17SVictor Perevertkin     if (DriverCount == 0) {
7918a978a17SVictor Perevertkin         stat = stat | (int)WdfIoQueueDriverNoRequests;
7928a978a17SVictor Perevertkin     }
7938a978a17SVictor Perevertkin 
7948a978a17SVictor Perevertkin     if(m_PowerManaged) {
7958a978a17SVictor Perevertkin 
7968a978a17SVictor Perevertkin         if (m_PowerState != FxIoQueuePowerOn) {
7978a978a17SVictor Perevertkin             stat = stat | (int)WdfIoQueuePnpHeld;
7988a978a17SVictor Perevertkin         }
7998a978a17SVictor Perevertkin     }
8008a978a17SVictor Perevertkin 
8018a978a17SVictor Perevertkin     return (WDF_IO_QUEUE_STATE)stat;
8028a978a17SVictor Perevertkin }
8038a978a17SVictor Perevertkin 
8048a978a17SVictor Perevertkin VOID
SetState(__in FX_IO_QUEUE_SET_STATE NewStatus)8058a978a17SVictor Perevertkin FxIoQueue::SetState(
8068a978a17SVictor Perevertkin     __in FX_IO_QUEUE_SET_STATE NewStatus
8078a978a17SVictor Perevertkin     )
8088a978a17SVictor Perevertkin {
8098a978a17SVictor Perevertkin    int AllowedBits;
8108a978a17SVictor Perevertkin 
8118a978a17SVictor Perevertkin    PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
8128a978a17SVictor Perevertkin 
8138a978a17SVictor Perevertkin    //
8148a978a17SVictor Perevertkin    // Only allow setting of valid bits
8158a978a17SVictor Perevertkin    //
8168a978a17SVictor Perevertkin    AllowedBits = (int)(FxIoQueueSetAcceptRequests     |
8178a978a17SVictor Perevertkin                        FxIoQueueClearAcceptRequests   |
8188a978a17SVictor Perevertkin                        FxIoQueueSetDispatchRequests   |
8198a978a17SVictor Perevertkin                        FxIoQueueClearDispatchRequests |
8208a978a17SVictor Perevertkin                        FxIoQueueSetShutdown           |
8218a978a17SVictor Perevertkin                        FxIoQueueClearShutdown
8228a978a17SVictor Perevertkin                        );
8238a978a17SVictor Perevertkin 
8248a978a17SVictor Perevertkin    if ((int)NewStatus & ~AllowedBits) {
8258a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
8268a978a17SVictor Perevertkin                            "Invalid WDFQUEUE 0x%p state",
8278a978a17SVictor Perevertkin                            GetObjectHandle());
8288a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
8298a978a17SVictor Perevertkin        return;
8308a978a17SVictor Perevertkin    }
8318a978a17SVictor Perevertkin 
8328a978a17SVictor Perevertkin    //
8338a978a17SVictor Perevertkin    // Clear the high bit used to prevent accidental mixing of
8348a978a17SVictor Perevertkin    // WDF_IO_QUEUE_STATE and FX_IO_QUEUE_SET_STATE
8358a978a17SVictor Perevertkin    //
8368a978a17SVictor Perevertkin    NewStatus = (FX_IO_QUEUE_SET_STATE)((int)NewStatus & 0x7FFFFFFF);
8378a978a17SVictor Perevertkin 
8388a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueClearShutdown) {
8398a978a17SVictor Perevertkin        m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)FxIoQueueShutdown);
8408a978a17SVictor Perevertkin    }
8418a978a17SVictor Perevertkin 
8428a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueSetShutdown) {
8438a978a17SVictor Perevertkin        m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)FxIoQueueShutdown);
8448a978a17SVictor Perevertkin    }
8458a978a17SVictor Perevertkin 
8468a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueSetAcceptRequests) {
8478a978a17SVictor Perevertkin        if (IsState(FxIoQueueShutdown) == FALSE) {
8488a978a17SVictor Perevertkin            m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)WdfIoQueueAcceptRequests);
8498a978a17SVictor Perevertkin        }
8508a978a17SVictor Perevertkin        else {
8518a978a17SVictor Perevertkin            DoTraceLevelMessage(FxDriverGlobals,
8528a978a17SVictor Perevertkin                                TRACE_LEVEL_INFORMATION, TRACINGIO,
8538a978a17SVictor Perevertkin                                "WDFQUEUE 0x%p is shut down, preventing queue "
8548a978a17SVictor Perevertkin                                "from accepting requests",
8558a978a17SVictor Perevertkin                                GetObjectHandle());
8568a978a17SVictor Perevertkin        }
8578a978a17SVictor Perevertkin    }
8588a978a17SVictor Perevertkin 
8598a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueClearAcceptRequests) {
8608a978a17SVictor Perevertkin        m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)WdfIoQueueAcceptRequests);
8618a978a17SVictor Perevertkin    }
8628a978a17SVictor Perevertkin 
8638a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueSetDispatchRequests) {
8648a978a17SVictor Perevertkin        m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)WdfIoQueueDispatchRequests);
8658a978a17SVictor Perevertkin        //
8668a978a17SVictor Perevertkin        // If the queue is allowed to dispatch new requests, we must clear this flag.
8678a978a17SVictor Perevertkin        // See also WdfIoQueueStopAndPurge for more info about the flag.
8688a978a17SVictor Perevertkin        //
8698a978a17SVictor Perevertkin        m_CancelDispatchedRequests = FALSE;
8708a978a17SVictor Perevertkin    }
8718a978a17SVictor Perevertkin 
8728a978a17SVictor Perevertkin    if (NewStatus & (int)FxIoQueueClearDispatchRequests) {
8738a978a17SVictor Perevertkin        m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)WdfIoQueueDispatchRequests);
8748a978a17SVictor Perevertkin    }
8758a978a17SVictor Perevertkin 
8768a978a17SVictor Perevertkin    return;
8778a978a17SVictor Perevertkin }
8788a978a17SVictor Perevertkin 
8798a978a17SVictor Perevertkin _Must_inspect_result_
8808a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyGetRequestUpdateFlags)8818a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyGetRequestUpdateFlags) (
8828a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
8838a978a17SVictor Perevertkin     _In_ FxRequest* TagRequest
8848a978a17SVictor Perevertkin     )
8858a978a17SVictor Perevertkin {
8868a978a17SVictor Perevertkin     KIRQL irql;
8878a978a17SVictor Perevertkin     NTSTATUS status;
8888a978a17SVictor Perevertkin 
8898a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
8908a978a17SVictor Perevertkin 
8918a978a17SVictor Perevertkin     if (TagRequest != NULL) {
8928a978a17SVictor Perevertkin         //
8938a978a17SVictor Perevertkin         // WdfIoQueueRetrieveFoundRequest is only valid on manual queues.
8948a978a17SVictor Perevertkin         // v1.11 and above: driver is not required to find the request
8958a978a17SVictor Perevertkin         //     using WdfIoQueueFindRequest.
8968a978a17SVictor Perevertkin         // v1.9 and below: driver is required to find the request
8978a978a17SVictor Perevertkin         //     using WdfIoQueueFindRequest.
8988a978a17SVictor Perevertkin         //
8998a978a17SVictor Perevertkin         if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
9008a978a17SVictor Perevertkin             if (m_Type != WdfIoQueueDispatchManual) {
9018a978a17SVictor Perevertkin                 status = STATUS_INVALID_DEVICE_REQUEST;
9028a978a17SVictor Perevertkin                 DoTraceLevelMessage(
9038a978a17SVictor Perevertkin                         FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
9048a978a17SVictor Perevertkin                         "WdfIoQueueRetrieveFoundRequest is allowed "
9058a978a17SVictor Perevertkin                         "only on a manual queue 0x%p, %!STATUS!",
9068a978a17SVictor Perevertkin                         GetHandle(), status);
9078a978a17SVictor Perevertkin                 FxVerifierDbgBreakPoint(FxDriverGlobals);
9088a978a17SVictor Perevertkin                 return status;
9098a978a17SVictor Perevertkin             }
9108a978a17SVictor Perevertkin         }
9118a978a17SVictor Perevertkin         else {
9128a978a17SVictor Perevertkin             //
9138a978a17SVictor Perevertkin             // Legacy validation.
9148a978a17SVictor Perevertkin             //
9158a978a17SVictor Perevertkin             TagRequest->Lock(&irql);
9168a978a17SVictor Perevertkin             status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals);
9178a978a17SVictor Perevertkin             TagRequest->Unlock(irql);
9188a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
9198a978a17SVictor Perevertkin                 return status;
9208a978a17SVictor Perevertkin             }
9218a978a17SVictor Perevertkin         }
9228a978a17SVictor Perevertkin     }
9238a978a17SVictor Perevertkin 
9248a978a17SVictor Perevertkin     Lock(&irql);
9258a978a17SVictor Perevertkin     if ((m_Type == WdfIoQueueDispatchSequential) && (m_DriverIoCount == 0)) {
9268a978a17SVictor Perevertkin 
9278a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
9288a978a17SVictor Perevertkin            "Driver called WdfIoQueueRetrieveNextRequest on a sequential WDFQUEUE 0x%p with no "
9298a978a17SVictor Perevertkin            "outstanding requests. This can cause a race with automatically dispatched "
9308a978a17SVictor Perevertkin            "requests. Call WdfIoQueueRetrieveNextRequest before completing the current request(s)",
9318a978a17SVictor Perevertkin            GetObjectHandle());
9328a978a17SVictor Perevertkin 
9338a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
9348a978a17SVictor Perevertkin 
9358a978a17SVictor Perevertkin        // Allow them to continue, though this is a race condition in their driver
9368a978a17SVictor Perevertkin     }
9378a978a17SVictor Perevertkin     Unlock(irql);
9388a978a17SVictor Perevertkin 
9398a978a17SVictor Perevertkin     return STATUS_SUCCESS;
9408a978a17SVictor Perevertkin }
9418a978a17SVictor Perevertkin 
9428a978a17SVictor Perevertkin VOID
FX_VF_METHOD(FxIoQueue,VerifyGetRequestRestoreFlags)9438a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyGetRequestRestoreFlags)(
9448a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
9458a978a17SVictor Perevertkin     _In_ FxRequest* pRequest
9468a978a17SVictor Perevertkin     )
9478a978a17SVictor Perevertkin {
9488a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(FxDriverGlobals);
9498a978a17SVictor Perevertkin     KIRQL irql;
9508a978a17SVictor Perevertkin 
9518a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
9528a978a17SVictor Perevertkin     pRequest->Lock(&irql);
9538a978a17SVictor Perevertkin 
9548a978a17SVictor Perevertkin     pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_TAG_REQUEST);
9558a978a17SVictor Perevertkin     pRequest->SetVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
9568a978a17SVictor Perevertkin 
9578a978a17SVictor Perevertkin     pRequest->Unlock(irql);
9588a978a17SVictor Perevertkin }
9598a978a17SVictor Perevertkin 
9608a978a17SVictor Perevertkin _Must_inspect_result_
9618a978a17SVictor Perevertkin NTSTATUS
GetRequest(__in_opt MdFileObject FileObject,__in_opt FxRequest * TagRequest,__deref_out FxRequest ** pOutRequest)9628a978a17SVictor Perevertkin FxIoQueue::GetRequest(
9638a978a17SVictor Perevertkin     __in_opt  MdFileObject FileObject,
9648a978a17SVictor Perevertkin     __in_opt  FxRequest*   TagRequest,
9658a978a17SVictor Perevertkin     __deref_out FxRequest**  pOutRequest
9668a978a17SVictor Perevertkin     )
9678a978a17SVictor Perevertkin /*++
9688a978a17SVictor Perevertkin 
9698a978a17SVictor Perevertkin Routine Description:
9708a978a17SVictor Perevertkin 
9718a978a17SVictor Perevertkin     This method is called by
9728a978a17SVictor Perevertkin 
9738a978a17SVictor Perevertkin         WdfIoQueueRetrieveNextRequest
9748a978a17SVictor Perevertkin         WdfIoQueueRetrieveRequestByFileObject
9758a978a17SVictor Perevertkin         WdfIoQueueRetrieveFoundRequest
9768a978a17SVictor Perevertkin 
9778a978a17SVictor Perevertkin      to retrieve a request from the queue.
9788a978a17SVictor Perevertkin 
9798a978a17SVictor Perevertkin Arguments:
9808a978a17SVictor Perevertkin 
9818a978a17SVictor Perevertkin Returns:
9828a978a17SVictor Perevertkin 
9838a978a17SVictor Perevertkin     NTSTATUS
9848a978a17SVictor Perevertkin 
9858a978a17SVictor Perevertkin --*/
9868a978a17SVictor Perevertkin {
9878a978a17SVictor Perevertkin     NTSTATUS   status;
9888a978a17SVictor Perevertkin     FxRequest*  pRequest = NULL;
9898a978a17SVictor Perevertkin     FxRequestCompletionState oldState;
9908a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
9918a978a17SVictor Perevertkin     KIRQL irql;
9928a978a17SVictor Perevertkin 
9938a978a17SVictor Perevertkin     status = VerifyGetRequestUpdateFlags(pFxDriverGlobals, TagRequest);
9948a978a17SVictor Perevertkin     if(!NT_SUCCESS(status)){
9958a978a17SVictor Perevertkin         return status;
9968a978a17SVictor Perevertkin     }
9978a978a17SVictor Perevertkin 
9988a978a17SVictor Perevertkin     //
9998a978a17SVictor Perevertkin     // Don't allow on parallel queues
10008a978a17SVictor Perevertkin     //
10018a978a17SVictor Perevertkin     if ((m_Type != WdfIoQueueDispatchManual) &&
10028a978a17SVictor Perevertkin         (m_Type != WdfIoQueueDispatchSequential)) {
10038a978a17SVictor Perevertkin         status = STATUS_INVALID_DEVICE_STATE;
10048a978a17SVictor Perevertkin         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
10058a978a17SVictor Perevertkin                 "Cannot be called on a parallel WDFQUEUE 0x%p, %!STATUS!",
10068a978a17SVictor Perevertkin                 GetObjectHandle(), status);
10078a978a17SVictor Perevertkin         return status;
10088a978a17SVictor Perevertkin     }
10098a978a17SVictor Perevertkin 
10108a978a17SVictor Perevertkin     Lock(&irql);
10118a978a17SVictor Perevertkin 
10128a978a17SVictor Perevertkin     //
10138a978a17SVictor Perevertkin     // Only if the queue state allows requests to be retrieved.
10148a978a17SVictor Perevertkin     // It's okay to retrieve requests while the queue is in a transitioning state.
10158a978a17SVictor Perevertkin     //
10168a978a17SVictor Perevertkin     if (m_PowerState == FxIoQueuePowerOff) {
10178a978a17SVictor Perevertkin         status = STATUS_WDF_PAUSED;
10188a978a17SVictor Perevertkin         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
10198a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is powered off, %!STATUS!",
10208a978a17SVictor Perevertkin                             GetObjectHandle(), status);
10218a978a17SVictor Perevertkin         Unlock(irql);
10228a978a17SVictor Perevertkin         return status;
10238a978a17SVictor Perevertkin     }
10248a978a17SVictor Perevertkin 
10258a978a17SVictor Perevertkin     //
10268a978a17SVictor Perevertkin     // See if the queue is (still) processing requests
10278a978a17SVictor Perevertkin     //
10288a978a17SVictor Perevertkin     if (!IsState(WdfIoQueueDispatchRequests)) {
10298a978a17SVictor Perevertkin         status = STATUS_WDF_PAUSED;
10308a978a17SVictor Perevertkin         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
10318a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is stopped, %!STATUS!",
10328a978a17SVictor Perevertkin                             GetObjectHandle(), status);
10338a978a17SVictor Perevertkin         Unlock(irql);
10348a978a17SVictor Perevertkin         return status;
10358a978a17SVictor Perevertkin     }
10368a978a17SVictor Perevertkin 
10378a978a17SVictor Perevertkin                                                 #pragma warning(disable:4127)
10388a978a17SVictor Perevertkin     while (TRUE) {
10398a978a17SVictor Perevertkin 
10408a978a17SVictor Perevertkin                                                 #pragma warning(default:4127)
10418a978a17SVictor Perevertkin         //
10428a978a17SVictor Perevertkin         // Get the next FxRequest from the cancel safe queue
10438a978a17SVictor Perevertkin         //
10448a978a17SVictor Perevertkin         status = FxRequest::GetNextRequest(&m_Queue, FileObject, TagRequest, &pRequest);
10458a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
10468a978a17SVictor Perevertkin             //
10478a978a17SVictor Perevertkin             // This code address the following race condition:
10488a978a17SVictor Perevertkin             // 1)  Queue has only one request (count 1).
10498a978a17SVictor Perevertkin             // 2)  Request in queue is cancelled.
10508a978a17SVictor Perevertkin             // 3)  Request's cancellation logic starts to run on thread 1.
10518a978a17SVictor Perevertkin             // 4)  But before cancellation logic gets the queue's lock
10528a978a17SVictor Perevertkin             //      thread 2 calls WdfIoQueueRetrieveNextRequest.
10538a978a17SVictor Perevertkin             // 5)  WdfIoQueueRetrieveNextRequest returns no more requests.
10548a978a17SVictor Perevertkin             //      Driver waits for the ReadyNotify callback. (count 1)
10558a978a17SVictor Perevertkin             // 6)  Thread 3 adds a new request in queue. (count 1->2)
10568a978a17SVictor Perevertkin             // 7)  Thread 1 finally runs. (count 2->1).
10578a978a17SVictor Perevertkin             // 8)  At this point driver stops responding b/c it never receives ReadyNotify.
10588a978a17SVictor Perevertkin             //
10598a978a17SVictor Perevertkin             // This code below forces the queue logic to send a ReadyNotify
10608a978a17SVictor Perevertkin             // callback the next time a new request is added (in step 6 above).
10618a978a17SVictor Perevertkin             //
10628a978a17SVictor Perevertkin             if (STATUS_NO_MORE_ENTRIES == status &&
10638a978a17SVictor Perevertkin                 NULL == FileObject && // WdfIoQueueRetrieveNextRequest
10648a978a17SVictor Perevertkin                 NULL == TagRequest && // WdfIoQueueRetrieveNextRequest
10658a978a17SVictor Perevertkin                 m_Queue.GetRequestCount() > 0L) {
10668a978a17SVictor Perevertkin 
10678a978a17SVictor Perevertkin                 m_ForceTransitionFromEmptyWhenAddingNewRequest = TRUE;
10688a978a17SVictor Perevertkin             }
10698a978a17SVictor Perevertkin 
10708a978a17SVictor Perevertkin             Unlock(irql);
10718a978a17SVictor Perevertkin             return status;
10728a978a17SVictor Perevertkin         }
10738a978a17SVictor Perevertkin 
10748a978a17SVictor Perevertkin         //
10758a978a17SVictor Perevertkin         // If we don't allow zero length read/write's to the driver,
10768a978a17SVictor Perevertkin         // complete it now with success and attempt to get another
10778a978a17SVictor Perevertkin         // request from the queue.
10788a978a17SVictor Perevertkin         //
10798a978a17SVictor Perevertkin         if (!m_AllowZeroLengthRequests) {
10808a978a17SVictor Perevertkin 
10818a978a17SVictor Perevertkin 
10828a978a17SVictor Perevertkin 
10838a978a17SVictor Perevertkin 
10848a978a17SVictor Perevertkin 
10858a978a17SVictor Perevertkin             (VOID)pRequest->GetCurrentIrpStackLocation();
10868a978a17SVictor Perevertkin 
10878a978a17SVictor Perevertkin             FxIrp* pIrp = pRequest->GetFxIrp();
10888a978a17SVictor Perevertkin             UCHAR majorFunction = pIrp->GetMajorFunction();
10898a978a17SVictor Perevertkin 
10908a978a17SVictor Perevertkin             if ((majorFunction == IRP_MJ_READ) &&
10918a978a17SVictor Perevertkin                 (pIrp->GetParameterReadLength() == 0)) {
10928a978a17SVictor Perevertkin 
10938a978a17SVictor Perevertkin                 Unlock(irql);
10948a978a17SVictor Perevertkin                 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
10958a978a17SVictor Perevertkin                     "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p",
10968a978a17SVictor Perevertkin                     pRequest->GetHandle(),GetObjectHandle());
10978a978a17SVictor Perevertkin                 pRequest->CompleteWithInformation(STATUS_SUCCESS, 0);
10988a978a17SVictor Perevertkin                 pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
10998a978a17SVictor Perevertkin 
11008a978a17SVictor Perevertkin                 Lock(&irql);
11018a978a17SVictor Perevertkin 
11028a978a17SVictor Perevertkin                 // Get another request from the queue
11038a978a17SVictor Perevertkin                 continue;
11048a978a17SVictor Perevertkin             }
11058a978a17SVictor Perevertkin             else if ((majorFunction == IRP_MJ_WRITE) &&
11068a978a17SVictor Perevertkin                      (pIrp->GetParameterWriteLength() == 0)) {
11078a978a17SVictor Perevertkin 
11088a978a17SVictor Perevertkin                 Unlock(irql);
11098a978a17SVictor Perevertkin                 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
11108a978a17SVictor Perevertkin                     "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p",
11118a978a17SVictor Perevertkin                     pRequest->GetHandle(), GetObjectHandle());
11128a978a17SVictor Perevertkin 
11138a978a17SVictor Perevertkin                 pRequest->CompleteWithInformation(STATUS_SUCCESS, 0);
11148a978a17SVictor Perevertkin                 pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
11158a978a17SVictor Perevertkin 
11168a978a17SVictor Perevertkin                 Lock(&irql);
11178a978a17SVictor Perevertkin 
11188a978a17SVictor Perevertkin                 // Get another request from the queue
11198a978a17SVictor Perevertkin                 continue;
11208a978a17SVictor Perevertkin             }
11218a978a17SVictor Perevertkin         }
11228a978a17SVictor Perevertkin 
11238a978a17SVictor Perevertkin         break;
11248a978a17SVictor Perevertkin     }
11258a978a17SVictor Perevertkin 
11268a978a17SVictor Perevertkin     // Increase the driver owned request count
11278a978a17SVictor Perevertkin     InsertInDriverOwnedList(pRequest);
11288a978a17SVictor Perevertkin 
11298a978a17SVictor Perevertkin     Unlock(irql);
11308a978a17SVictor Perevertkin 
11318a978a17SVictor Perevertkin     //
11328a978a17SVictor Perevertkin     // We don't need to check for PurgeComplete since
11338a978a17SVictor Perevertkin     // we are giving the request to the driver
11348a978a17SVictor Perevertkin     //
11358a978a17SVictor Perevertkin 
11368a978a17SVictor Perevertkin     // pRequest is not cancellable now
11378a978a17SVictor Perevertkin 
11388a978a17SVictor Perevertkin     //
11398a978a17SVictor Perevertkin     // We are now going to return the request
11408a978a17SVictor Perevertkin     // to the driver, and it must complete it.
11418a978a17SVictor Perevertkin     //
11428a978a17SVictor Perevertkin 
11438a978a17SVictor Perevertkin     //
11448a978a17SVictor Perevertkin     // Set a completion event, this takes a reference
11458a978a17SVictor Perevertkin     //
11468a978a17SVictor Perevertkin     oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
11478a978a17SVictor Perevertkin     ASSERT(oldState == FxRequestCompletionStateNone);
11488a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(oldState);
11498a978a17SVictor Perevertkin 
11508a978a17SVictor Perevertkin     //
11518a978a17SVictor Perevertkin     // Track that we have given the request to the driver
11528a978a17SVictor Perevertkin     //
11538a978a17SVictor Perevertkin     VerifyGetRequestRestoreFlags(pFxDriverGlobals, pRequest);
11548a978a17SVictor Perevertkin 
11558a978a17SVictor Perevertkin     pRequest->SetPresented();
11568a978a17SVictor Perevertkin 
11578a978a17SVictor Perevertkin     //
11588a978a17SVictor Perevertkin     // Release our original reference. The FxRequest::Complete
11598a978a17SVictor Perevertkin     // will release the final one since we have registered a completion
11608a978a17SVictor Perevertkin     // callback handler
11618a978a17SVictor Perevertkin     //
11628a978a17SVictor Perevertkin     // We now have one reference count on the FxRequest object until
11638a978a17SVictor Perevertkin     // its completion routine runs since the completion event made
11648a978a17SVictor Perevertkin     // an extra reference, and will dereference it when it fires, or
11658a978a17SVictor Perevertkin     // its canceled.
11668a978a17SVictor Perevertkin     //
11678a978a17SVictor Perevertkin 
11688a978a17SVictor Perevertkin     pRequest->RELEASE(FXREQUEST_STATE_TAG);
11698a978a17SVictor Perevertkin 
11708a978a17SVictor Perevertkin     // Return it to the driver
11718a978a17SVictor Perevertkin     *pOutRequest = pRequest;
11728a978a17SVictor Perevertkin 
11738a978a17SVictor Perevertkin     return STATUS_SUCCESS;
11748a978a17SVictor Perevertkin }
11758a978a17SVictor Perevertkin 
11768a978a17SVictor Perevertkin _Must_inspect_result_
11778a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyPeekRequest)11788a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyPeekRequest) (
11798a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
11808a978a17SVictor Perevertkin     _In_ FxRequest* TagRequest
11818a978a17SVictor Perevertkin     )
11828a978a17SVictor Perevertkin {
11838a978a17SVictor Perevertkin     NTSTATUS status;
11848a978a17SVictor Perevertkin     KIRQL irql;
11858a978a17SVictor Perevertkin 
11868a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
11878a978a17SVictor Perevertkin 
11888a978a17SVictor Perevertkin     TagRequest->Lock(&irql);
11898a978a17SVictor Perevertkin     status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals);
11908a978a17SVictor Perevertkin     TagRequest->Unlock(irql);
11918a978a17SVictor Perevertkin 
11928a978a17SVictor Perevertkin     return status;
11938a978a17SVictor Perevertkin }
11948a978a17SVictor Perevertkin 
11958a978a17SVictor Perevertkin _Must_inspect_result_
11968a978a17SVictor Perevertkin NTSTATUS
PeekRequest(__in_opt FxRequest * TagRequest,__in_opt MdFileObject FileObject,__out_opt PWDF_REQUEST_PARAMETERS Parameters,__deref_out FxRequest ** pOutRequest)11978a978a17SVictor Perevertkin FxIoQueue::PeekRequest(
11988a978a17SVictor Perevertkin     __in_opt  FxRequest*          TagRequest,
11998a978a17SVictor Perevertkin     __in_opt  MdFileObject        FileObject,
12008a978a17SVictor Perevertkin     __out_opt PWDF_REQUEST_PARAMETERS Parameters,
12018a978a17SVictor Perevertkin     __deref_out FxRequest**         pOutRequest
12028a978a17SVictor Perevertkin     )
12038a978a17SVictor Perevertkin /*++
12048a978a17SVictor Perevertkin 
12058a978a17SVictor Perevertkin Routine Description:
12068a978a17SVictor Perevertkin 
12078a978a17SVictor Perevertkin     This method is called by WdfIoQueueFindRequest to
12088a978a17SVictor Perevertkin     look for a specific request from the queue. If tagrequest
12098a978a17SVictor Perevertkin     is not specified then this method will return the very
12108a978a17SVictor Perevertkin     first request from the queue.
12118a978a17SVictor Perevertkin 
12128a978a17SVictor Perevertkin     If the fileobject is specified then fileobject is also
12138a978a17SVictor Perevertkin     used as one of the constrain for returing the request.
12148a978a17SVictor Perevertkin 
12158a978a17SVictor Perevertkin     Important point to remember is that only request information
12168a978a17SVictor Perevertkin     is returned to the caller. The request is still present in
12178a978a17SVictor Perevertkin     the queue.
12188a978a17SVictor Perevertkin 
12198a978a17SVictor Perevertkin     If the request is returned, there is an additional reference
12208a978a17SVictor Perevertkin     taken on the queue to prevent it from deletion while the
12218a978a17SVictor Perevertkin     caller is using the request handle. The caller has to
12228a978a17SVictor Perevertkin     explicitly drop the reference once he is done using the
12238a978a17SVictor Perevertkin     request handle.
12248a978a17SVictor Perevertkin 
12258a978a17SVictor Perevertkin Arguments:
12268a978a17SVictor Perevertkin 
12278a978a17SVictor Perevertkin Returns:
12288a978a17SVictor Perevertkin 
12298a978a17SVictor Perevertkin     NTSTATUS
12308a978a17SVictor Perevertkin 
12318a978a17SVictor Perevertkin --*/
12328a978a17SVictor Perevertkin 
12338a978a17SVictor Perevertkin {
12348a978a17SVictor Perevertkin     NTSTATUS   status;
12358a978a17SVictor Perevertkin     FxRequest*  pRequest = NULL;
12368a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
12378a978a17SVictor Perevertkin     KIRQL irql;
12388a978a17SVictor Perevertkin 
12398a978a17SVictor Perevertkin     //
12408a978a17SVictor Perevertkin     // FindRequest is allowed only on a manual queue.
12418a978a17SVictor Perevertkin     //
12428a978a17SVictor Perevertkin     if (m_Type != WdfIoQueueDispatchManual) {
12438a978a17SVictor Perevertkin         status = STATUS_INVALID_DEVICE_REQUEST;
12448a978a17SVictor Perevertkin         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
12458a978a17SVictor Perevertkin                "FindRequest is allowed only on a manaul queue 0x%p, %!STATUS!",
12468a978a17SVictor Perevertkin                GetHandle(), status);
12478a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(pFxDriverGlobals);
12488a978a17SVictor Perevertkin         return status;
12498a978a17SVictor Perevertkin     }
12508a978a17SVictor Perevertkin 
12518a978a17SVictor Perevertkin     if (TagRequest != NULL) {
12528a978a17SVictor Perevertkin         status = VerifyPeekRequest(pFxDriverGlobals, TagRequest);
12538a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
12548a978a17SVictor Perevertkin             return status;
12558a978a17SVictor Perevertkin         }
12568a978a17SVictor Perevertkin     }
12578a978a17SVictor Perevertkin 
12588a978a17SVictor Perevertkin     //
12598a978a17SVictor Perevertkin     // Get the next FxRequest from the cancel safe queue
12608a978a17SVictor Perevertkin     //
12618a978a17SVictor Perevertkin     // If success, it will return a referenced FxRequest in
12628a978a17SVictor Perevertkin     // which the caller must release the reference.
12638a978a17SVictor Perevertkin     //
12648a978a17SVictor Perevertkin     Lock(&irql);
12658a978a17SVictor Perevertkin 
12668a978a17SVictor Perevertkin     status = FxRequest::PeekRequest(
12678a978a17SVictor Perevertkin                             &m_Queue,
12688a978a17SVictor Perevertkin                             TagRequest,
12698a978a17SVictor Perevertkin                             FileObject,
12708a978a17SVictor Perevertkin                             Parameters,
12718a978a17SVictor Perevertkin                             &pRequest
12728a978a17SVictor Perevertkin                             );
12738a978a17SVictor Perevertkin 
12748a978a17SVictor Perevertkin     //
12758a978a17SVictor Perevertkin     // This code address the following potential race condition:
12768a978a17SVictor Perevertkin     // 1)  Queue has only one request (count 1).
12778a978a17SVictor Perevertkin     // 2)  Request in queue is cancelled.
12788a978a17SVictor Perevertkin     // 3)  Request's cancellation logic starts to run on thread 1.
12798a978a17SVictor Perevertkin     // 4)  But before cancellation logic gets the queue's lock
12808a978a17SVictor Perevertkin     //      thread 2 calls WdfIoQueueFindRequest to find any request.
12818a978a17SVictor Perevertkin     // 5)  WdfIoQueueFindRequest returns no more requests.
12828a978a17SVictor Perevertkin     //      Driver waits for the ReadyNotify callback. (count 1)
12838a978a17SVictor Perevertkin     // 6)  Thread 3 adds a new request in queue. (count 1->2)
12848a978a17SVictor Perevertkin     // 7)  Thread 1 finally runs. (count 2->1).
12858a978a17SVictor Perevertkin     // 8)  At this point driver stops responding b/c it never receives ReadyNotify.
12868a978a17SVictor Perevertkin     //
12878a978a17SVictor Perevertkin     // This code below forces the queue logic to send a ReadyNotify
12888a978a17SVictor Perevertkin     // callback the next time a new request is added (in step 6 above).
12898a978a17SVictor Perevertkin     //
12908a978a17SVictor Perevertkin     if (STATUS_NO_MORE_ENTRIES == status &&
12918a978a17SVictor Perevertkin         NULL == FileObject && // WdfIoQueueFindRequest(any request)
12928a978a17SVictor Perevertkin         NULL == TagRequest && // WdfIoQueueFindRequest(any request)
12938a978a17SVictor Perevertkin         m_Queue.GetRequestCount() > 0L) {
12948a978a17SVictor Perevertkin 
12958a978a17SVictor Perevertkin         m_ForceTransitionFromEmptyWhenAddingNewRequest = TRUE;
12968a978a17SVictor Perevertkin     }
12978a978a17SVictor Perevertkin 
12988a978a17SVictor Perevertkin     Unlock(irql);
12998a978a17SVictor Perevertkin 
13008a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
13018a978a17SVictor Perevertkin         return status;
13028a978a17SVictor Perevertkin     }
13038a978a17SVictor Perevertkin 
13048a978a17SVictor Perevertkin     //
13058a978a17SVictor Perevertkin     // Mark it as a tag request to detect abuse since its not
13068a978a17SVictor Perevertkin     // driver owned.
13078a978a17SVictor Perevertkin     //
13088a978a17SVictor Perevertkin     if (pFxDriverGlobals->FxVerifierOn) {
13098a978a17SVictor Perevertkin         pRequest->SetVerifierFlags(FXREQUEST_FLAG_TAG_REQUEST);
13108a978a17SVictor Perevertkin     }
13118a978a17SVictor Perevertkin 
13128a978a17SVictor Perevertkin     // Return it to the driver
13138a978a17SVictor Perevertkin     *pOutRequest = pRequest;
13148a978a17SVictor Perevertkin 
13158a978a17SVictor Perevertkin     return status;
13168a978a17SVictor Perevertkin }
13178a978a17SVictor Perevertkin 
13188a978a17SVictor Perevertkin SHORT
FX_VF_METHOD(FxIoQueue,VerifyForwardRequestUpdateFlags)13198a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyForwardRequestUpdateFlags) (
13208a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
13218a978a17SVictor Perevertkin     _In_ FxRequest* Request
13228a978a17SVictor Perevertkin     )
13238a978a17SVictor Perevertkin {
13248a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(FxDriverGlobals);
13258a978a17SVictor Perevertkin     SHORT OldFlags = 0;
13268a978a17SVictor Perevertkin     KIRQL irql;
13278a978a17SVictor Perevertkin 
13288a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
13298a978a17SVictor Perevertkin 
13308a978a17SVictor Perevertkin     Request->Lock(&irql);
13318a978a17SVictor Perevertkin 
13328a978a17SVictor Perevertkin     // Save old flags to put them back if forward fails
13338a978a17SVictor Perevertkin     OldFlags = Request->GetVerifierFlagsLocked();
13348a978a17SVictor Perevertkin 
13358a978a17SVictor Perevertkin     //
13368a978a17SVictor Perevertkin     // Set that the request was forwarded. This effects
13378a978a17SVictor Perevertkin     // cancel behavior.
13388a978a17SVictor Perevertkin     //
13398a978a17SVictor Perevertkin     Request->SetVerifierFlagsLocked(FXREQUEST_FLAG_FORWARDED);
13408a978a17SVictor Perevertkin 
13418a978a17SVictor Perevertkin     ASSERT((Request->GetVerifierFlagsLocked() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
13428a978a17SVictor Perevertkin 
13438a978a17SVictor Perevertkin     // Set that the request is no longer driver owned
13448a978a17SVictor Perevertkin     Request->ClearVerifierFlagsLocked(
13458a978a17SVictor Perevertkin         FXREQUEST_FLAG_DRIVER_OWNED | FXREQUEST_FLAG_DRIVER_DISPATCH);
13468a978a17SVictor Perevertkin 
13478a978a17SVictor Perevertkin     Request->Unlock(irql);
13488a978a17SVictor Perevertkin 
13498a978a17SVictor Perevertkin     return OldFlags;
13508a978a17SVictor Perevertkin }
13518a978a17SVictor Perevertkin 
13528a978a17SVictor Perevertkin _Must_inspect_result_
13538a978a17SVictor Perevertkin NTSTATUS
ForwardRequestWorker(__in FxRequest * Request,__in FxIoQueue * DestQueue)13548a978a17SVictor Perevertkin FxIoQueue::ForwardRequestWorker(
13558a978a17SVictor Perevertkin     __in FxRequest* Request,
13568a978a17SVictor Perevertkin     __in FxIoQueue* DestQueue
13578a978a17SVictor Perevertkin     )
13588a978a17SVictor Perevertkin {
13598a978a17SVictor Perevertkin     NTSTATUS status;
13608a978a17SVictor Perevertkin     FxRequestCompletionState oldState;
13618a978a17SVictor Perevertkin     PLIST_ENTRY ple;
13628a978a17SVictor Perevertkin     SHORT     OldFlags;
13638a978a17SVictor Perevertkin     KIRQL irql;
13648a978a17SVictor Perevertkin 
13658a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
13668a978a17SVictor Perevertkin 
13678a978a17SVictor Perevertkin     OldFlags = 0;
13688a978a17SVictor Perevertkin 
13698a978a17SVictor Perevertkin     //
13708a978a17SVictor Perevertkin     // The request has only one reference, held by the completion
13718a978a17SVictor Perevertkin     // callback function. We need to take another one before cancelling
13728a978a17SVictor Perevertkin     // this function, otherwise we will lose the request object
13738a978a17SVictor Perevertkin     //
13748a978a17SVictor Perevertkin     Request->ADDREF(FXREQUEST_STATE_TAG);
13758a978a17SVictor Perevertkin 
13768a978a17SVictor Perevertkin     //
13778a978a17SVictor Perevertkin     // Cancel its current completion event for this queue
13788a978a17SVictor Perevertkin     //
13798a978a17SVictor Perevertkin     oldState = Request->SetCompletionState(FxRequestCompletionStateNone);
13808a978a17SVictor Perevertkin     ASSERT(oldState == FxRequestCompletionStateQueue);
13818a978a17SVictor Perevertkin 
13828a978a17SVictor Perevertkin     OldFlags = VerifyForwardRequestUpdateFlags(FxDriverGlobals, Request);
13838a978a17SVictor Perevertkin 
13848a978a17SVictor Perevertkin     //
13858a978a17SVictor Perevertkin     // Remove it from this queues driver owned list.
13868a978a17SVictor Perevertkin     //
13878a978a17SVictor Perevertkin     // This must be done before forward since new queue will
13888a978a17SVictor Perevertkin     // use the list entry in the FxRequest
13898a978a17SVictor Perevertkin     //
13908a978a17SVictor Perevertkin     // We can't use RemoveFromDriverOwnedList since we want the
13918a978a17SVictor Perevertkin     // m_DriverIoCount to be left alone in case the forward fails.
13928a978a17SVictor Perevertkin     // If we don't, another thread can run when we drop the lock, notice
13938a978a17SVictor Perevertkin     // that there are no more requests, and raise the purged and empty
13948a978a17SVictor Perevertkin     // events. But if the forward fails, the request will wind up back
13958a978a17SVictor Perevertkin     // on the queue! So m_DriverIoCount is used as a gate to prevent
13968a978a17SVictor Perevertkin     // these events from firing until we are really sure this queue
13978a978a17SVictor Perevertkin     // is done with the request.
13988a978a17SVictor Perevertkin     //
13998a978a17SVictor Perevertkin 
14008a978a17SVictor Perevertkin 
14018a978a17SVictor Perevertkin 
14028a978a17SVictor Perevertkin 
14038a978a17SVictor Perevertkin 
14048a978a17SVictor Perevertkin 
14058a978a17SVictor Perevertkin 
14068a978a17SVictor Perevertkin 
14078a978a17SVictor Perevertkin 
14088a978a17SVictor Perevertkin 
14098a978a17SVictor Perevertkin 
14108a978a17SVictor Perevertkin     Lock(&irql);
14118a978a17SVictor Perevertkin     ple = Request->GetListEntry(FxListEntryDriverOwned);
14128a978a17SVictor Perevertkin     RemoveEntryList(ple);
14138a978a17SVictor Perevertkin     InitializeListHead(ple);
14148a978a17SVictor Perevertkin     Unlock(irql);
14158a978a17SVictor Perevertkin 
14168a978a17SVictor Perevertkin     //
14178a978a17SVictor Perevertkin     // Attempt to pass the request onto the target queue
14188a978a17SVictor Perevertkin     //
14198a978a17SVictor Perevertkin     status = DestQueue->QueueRequestFromForward(Request);
14208a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
14218a978a17SVictor Perevertkin 
14228a978a17SVictor Perevertkin         //
14238a978a17SVictor Perevertkin         // Target queue did not accept the request, so we
14248a978a17SVictor Perevertkin         // restore the original completion callback function
14258a978a17SVictor Perevertkin         // and flags
14268a978a17SVictor Perevertkin         //
14278a978a17SVictor Perevertkin         oldState = Request->SetCompletionState(oldState);
14288a978a17SVictor Perevertkin         ASSERT(oldState == FxRequestCompletionStateNone);
14298a978a17SVictor Perevertkin         UNREFERENCED_PARAMETER(oldState);
14308a978a17SVictor Perevertkin 
14318a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
14328a978a17SVictor Perevertkin             Request->SetVerifierFlags(OldFlags);
14338a978a17SVictor Perevertkin         }
14348a978a17SVictor Perevertkin 
14358a978a17SVictor Perevertkin         // Release the extra reference we took
14368a978a17SVictor Perevertkin         Request->RELEASE(FXREQUEST_STATE_TAG);
14378a978a17SVictor Perevertkin 
14388a978a17SVictor Perevertkin         Lock(&irql);
14398a978a17SVictor Perevertkin         // Place it back on the driver owned list
14408a978a17SVictor Perevertkin         InsertTailList(&m_DriverOwned, ple);
14418a978a17SVictor Perevertkin         Unlock(irql);
14428a978a17SVictor Perevertkin     }
14438a978a17SVictor Perevertkin     else {
14448a978a17SVictor Perevertkin 
14458a978a17SVictor Perevertkin         Lock(&irql);
14468a978a17SVictor Perevertkin 
14478a978a17SVictor Perevertkin         // Request is no longer part of the I/O count for this queue
14488a978a17SVictor Perevertkin         m_DriverIoCount--;
14498a978a17SVictor Perevertkin 
14508a978a17SVictor Perevertkin         ASSERT(m_DriverIoCount >= 0);
14518a978a17SVictor Perevertkin 
14528a978a17SVictor Perevertkin         //
14538a978a17SVictor Perevertkin         // Don't run the event dispatcher if we are called from a
14548a978a17SVictor Perevertkin         // dispath routine in order to prevent stack recursion.
14558a978a17SVictor Perevertkin         // Since some other thread (possibly this thread higher on
14568a978a17SVictor Perevertkin         // the stack) is running the dispatcher, no events will get lost.
14578a978a17SVictor Perevertkin         //
14588a978a17SVictor Perevertkin         //
14598a978a17SVictor Perevertkin         // This returns with the IoQueue lock released
14608a978a17SVictor Perevertkin         //
14618a978a17SVictor Perevertkin         DispatchInternalEvents(irql);
14628a978a17SVictor Perevertkin 
14638a978a17SVictor Perevertkin         //
14648a978a17SVictor Perevertkin         // We don't dereference the request object since the new IoQueue
14658a978a17SVictor Perevertkin         // will release it when it is done.
14668a978a17SVictor Perevertkin         //
14678a978a17SVictor Perevertkin     }
14688a978a17SVictor Perevertkin 
14698a978a17SVictor Perevertkin     return status;
14708a978a17SVictor Perevertkin }
14718a978a17SVictor Perevertkin 
14728a978a17SVictor Perevertkin _Must_inspect_result_
14738a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyForwardRequestToParent)14748a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyForwardRequestToParent) (
14758a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
14768a978a17SVictor Perevertkin     _In_ FxIoQueue* DestQueue,
14778a978a17SVictor Perevertkin     _In_ FxRequest* Request
14788a978a17SVictor Perevertkin     )
14798a978a17SVictor Perevertkin {
14808a978a17SVictor Perevertkin     KIRQL irql;
14818a978a17SVictor Perevertkin     NTSTATUS status;
14828a978a17SVictor Perevertkin 
14838a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
14848a978a17SVictor Perevertkin 
14858a978a17SVictor Perevertkin     if (m_Device->m_ParentDevice == NULL) {
14868a978a17SVictor Perevertkin        status = STATUS_INVALID_DEVICE_REQUEST;
14878a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
14888a978a17SVictor Perevertkin                "No parent device for WDFQUEUE 0x%p Device, %!STATUS!",
14898a978a17SVictor Perevertkin                 DestQueue->m_Device->GetHandle(), status);
14908a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
14918a978a17SVictor Perevertkin        goto Done;
14928a978a17SVictor Perevertkin     }
14938a978a17SVictor Perevertkin 
14948a978a17SVictor Perevertkin     Request->Lock(&irql);
14958a978a17SVictor Perevertkin 
14968a978a17SVictor Perevertkin     status = Request->VerifyRequestIsDriverOwned(FxDriverGlobals);
14978a978a17SVictor Perevertkin 
14988a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
14998a978a17SVictor Perevertkin        status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals);
15008a978a17SVictor Perevertkin     }
15018a978a17SVictor Perevertkin 
15028a978a17SVictor Perevertkin     Request->Unlock(irql);
15038a978a17SVictor Perevertkin 
15048a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
15058a978a17SVictor Perevertkin        goto Done;
15068a978a17SVictor Perevertkin     }
15078a978a17SVictor Perevertkin 
15088a978a17SVictor Perevertkin     if (DestQueue == this) {
15098a978a17SVictor Perevertkin        status = STATUS_INVALID_DEVICE_REQUEST;
15108a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
15118a978a17SVictor Perevertkin                            "Cannot forward a request to the same WDFQUEUE 0x%p"
15128a978a17SVictor Perevertkin                            " %!STATUS!", GetObjectHandle(), status);
15138a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
15148a978a17SVictor Perevertkin        goto Done;
15158a978a17SVictor Perevertkin     }
15168a978a17SVictor Perevertkin 
15178a978a17SVictor Perevertkin     if (m_Device->m_ParentDevice != DestQueue->m_Device) {
15188a978a17SVictor Perevertkin        status = STATUS_INVALID_DEVICE_REQUEST;
15198a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
15208a978a17SVictor Perevertkin                            "Cannot forward a request to "
15218a978a17SVictor Perevertkin                            "a different WDFDEVICE 0x%p which is not the "
15228a978a17SVictor Perevertkin                            "parent, %!STATUS!",
15238a978a17SVictor Perevertkin                             DestQueue->m_Device->GetHandle(),
15248a978a17SVictor Perevertkin                             status);
15258a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
15268a978a17SVictor Perevertkin        goto Done;
15278a978a17SVictor Perevertkin     }
15288a978a17SVictor Perevertkin 
15298a978a17SVictor Perevertkin     if (Request->IsReserved()) {
15308a978a17SVictor Perevertkin        status = STATUS_INVALID_DEVICE_REQUEST;
15318a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
15328a978a17SVictor Perevertkin                            "Cannot forward reserved WDFREQUEST 0x%p to a "
15338a978a17SVictor Perevertkin                            "parent WDFDEVICE 0x%p, %!STATUS!",
15348a978a17SVictor Perevertkin                            Request->GetHandle(),
15358a978a17SVictor Perevertkin                            DestQueue->m_Device->GetHandle(),
15368a978a17SVictor Perevertkin                            status);
15378a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
15388a978a17SVictor Perevertkin        goto Done;
15398a978a17SVictor Perevertkin     }
15408a978a17SVictor Perevertkin 
15418a978a17SVictor Perevertkin     //
15428a978a17SVictor Perevertkin     // Make sure the child device is a PDO
15438a978a17SVictor Perevertkin     //
15448a978a17SVictor Perevertkin     ASSERT(m_Device->IsPdo());
15458a978a17SVictor Perevertkin 
15468a978a17SVictor Perevertkin     //
15478a978a17SVictor Perevertkin     // Check if the WdfPdoInitSetForwardRequestToParent was called to increase
15488a978a17SVictor Perevertkin     // the StackSize of the child Device  to include the stack size of the
15498a978a17SVictor Perevertkin     // parent Device
15508a978a17SVictor Perevertkin     //
15518a978a17SVictor Perevertkin     if (m_Device->IsPnp()
15528a978a17SVictor Perevertkin        &&
15538a978a17SVictor Perevertkin        m_Device->GetPdoPkg()->m_AllowForwardRequestToParent == FALSE) {
15548a978a17SVictor Perevertkin        status = STATUS_INVALID_DEVICE_REQUEST;
15558a978a17SVictor Perevertkin        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
15568a978a17SVictor Perevertkin            "WdfPdoInitSetForwardRequestToParent not called on "
15578a978a17SVictor Perevertkin            "WDFDEVICE 0x%p, %!STATUS!", m_Device->GetHandle(),
15588a978a17SVictor Perevertkin            status);
15598a978a17SVictor Perevertkin        FxVerifierDbgBreakPoint(FxDriverGlobals);
15608a978a17SVictor Perevertkin        goto Done;
15618a978a17SVictor Perevertkin     }
15628a978a17SVictor Perevertkin 
15638a978a17SVictor Perevertkin Done:
15648a978a17SVictor Perevertkin     return status;
15658a978a17SVictor Perevertkin }
15668a978a17SVictor Perevertkin 
15678a978a17SVictor Perevertkin _Must_inspect_result_
15688a978a17SVictor Perevertkin NTSTATUS
ForwardRequestToParent(__in FxIoQueue * DestQueue,__in FxRequest * Request,__in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions)15698a978a17SVictor Perevertkin FxIoQueue::ForwardRequestToParent(
15708a978a17SVictor Perevertkin     __in FxIoQueue* DestQueue,
15718a978a17SVictor Perevertkin     __in FxRequest* Request,
15728a978a17SVictor Perevertkin     __in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions
15738a978a17SVictor Perevertkin     )
15748a978a17SVictor Perevertkin 
15758a978a17SVictor Perevertkin /*++
15768a978a17SVictor Perevertkin 
15778a978a17SVictor Perevertkin Routine Description:
15788a978a17SVictor Perevertkin 
15798a978a17SVictor Perevertkin     ForwardRequest is called from the drivers EvtIoDefault routine
15808a978a17SVictor Perevertkin     and the following conditions apply:
15818a978a17SVictor Perevertkin 
15828a978a17SVictor Perevertkin     Request is not on a CSQ and not cancellable
15838a978a17SVictor Perevertkin 
15848a978a17SVictor Perevertkin     Request is FXREQUEST_FLAG_DRIVER_OWNED
15858a978a17SVictor Perevertkin 
15868a978a17SVictor Perevertkin     m_DriverIoCount has been incremented to reflect the request
15878a978a17SVictor Perevertkin 
15888a978a17SVictor Perevertkin     Request has an I/O completion callback function pointing to
15898a978a17SVictor Perevertkin     FxIoQueueRequestComplete with the context for this Queue
15908a978a17SVictor Perevertkin 
15918a978a17SVictor Perevertkin     The Request has one reference count from the I/O completion callback.
15928a978a17SVictor Perevertkin 
15938a978a17SVictor Perevertkin     If a driver calls this API, it will not complete the request
15948a978a17SVictor Perevertkin     as a result of this queues EvtIoDefault, and does not own
15958a978a17SVictor Perevertkin     the request until it has been re-presented by the Destination
15968a978a17SVictor Perevertkin     Queue.
15978a978a17SVictor Perevertkin 
15988a978a17SVictor Perevertkin Arguments:
15998a978a17SVictor Perevertkin 
16008a978a17SVictor Perevertkin Returns:
16018a978a17SVictor Perevertkin 
16028a978a17SVictor Perevertkin     NTSTATUS
16038a978a17SVictor Perevertkin 
16048a978a17SVictor Perevertkin --*/
16058a978a17SVictor Perevertkin {
16068a978a17SVictor Perevertkin     NTSTATUS status;
16078a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
16088a978a17SVictor Perevertkin     BOOLEAN  forwardRequestToParent;
16098a978a17SVictor Perevertkin     FxIrp* pIrp;
16108a978a17SVictor Perevertkin 
16118a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(ForwardOptions);
16128a978a17SVictor Perevertkin 
16138a978a17SVictor Perevertkin     pFxDriverGlobals = GetDriverGlobals();
16148a978a17SVictor Perevertkin 
16158a978a17SVictor Perevertkin     forwardRequestToParent = Request->m_ForwardRequestToParent;
16168a978a17SVictor Perevertkin 
16178a978a17SVictor Perevertkin     status = VerifyForwardRequestToParent(pFxDriverGlobals,
16188a978a17SVictor Perevertkin                                           DestQueue,
16198a978a17SVictor Perevertkin                                           Request);
16208a978a17SVictor Perevertkin     if(!NT_SUCCESS(status)){
16218a978a17SVictor Perevertkin         return status;
16228a978a17SVictor Perevertkin     }
16238a978a17SVictor Perevertkin 
16248a978a17SVictor Perevertkin     pIrp = Request->GetFxIrp();
16258a978a17SVictor Perevertkin 
16268a978a17SVictor Perevertkin     pIrp->CopyCurrentIrpStackLocationToNext();
16278a978a17SVictor Perevertkin     pIrp->SetNextIrpStackLocation();
16288a978a17SVictor Perevertkin 
16298a978a17SVictor Perevertkin     //
16308a978a17SVictor Perevertkin     // Save a pointer to the device object for this request so that it can
16318a978a17SVictor Perevertkin     // be used later in completion.
16328a978a17SVictor Perevertkin     //
16338a978a17SVictor Perevertkin     pIrp->SetCurrentDeviceObject(m_Device->m_ParentDevice->GetDeviceObject());
16348a978a17SVictor Perevertkin 
16358a978a17SVictor Perevertkin     Request->SetDeviceBase((CfxDeviceBase *)m_Device->m_ParentDevice);
16368a978a17SVictor Perevertkin     Request->m_ForwardRequestToParent = TRUE;
16378a978a17SVictor Perevertkin 
16388a978a17SVictor Perevertkin     status = ForwardRequestWorker(Request, DestQueue);
16398a978a17SVictor Perevertkin 
16408a978a17SVictor Perevertkin     //
16418a978a17SVictor Perevertkin     // Undo the actions of changing the FxDevice and
16428a978a17SVictor Perevertkin     // changing the deviceObject and stack location in the IRP
16438a978a17SVictor Perevertkin     //
16448a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
16458a978a17SVictor Perevertkin         Request->SetDeviceBase((CfxDeviceBase *)m_Device);
16468a978a17SVictor Perevertkin         pIrp = Request->GetFxIrp();
16478a978a17SVictor Perevertkin         pIrp->SkipCurrentIrpStackLocation();
16488a978a17SVictor Perevertkin         ASSERT(pIrp->GetDeviceObject() == m_Device->GetDeviceObject());
16498a978a17SVictor Perevertkin 
16508a978a17SVictor Perevertkin         //
16518a978a17SVictor Perevertkin         // Set the value of m_ForwardRequestToParent to the previous
16528a978a17SVictor Perevertkin         // value so that if the Request has been forwarded to Parent
16538a978a17SVictor Perevertkin         // successfully but fails to be forwarded to the grandparent
16548a978a17SVictor Perevertkin         // from the parent then we free it back using ExFreePool
16558a978a17SVictor Perevertkin         // instead of the Lookaside buffer .
16568a978a17SVictor Perevertkin         //
16578a978a17SVictor Perevertkin         Request->m_ForwardRequestToParent = forwardRequestToParent;
16588a978a17SVictor Perevertkin     }
16598a978a17SVictor Perevertkin 
16608a978a17SVictor Perevertkin     return status;
16618a978a17SVictor Perevertkin }
16628a978a17SVictor Perevertkin 
16638a978a17SVictor Perevertkin _Must_inspect_result_
16648a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyForwardRequest)16658a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyForwardRequest) (
16668a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
16678a978a17SVictor Perevertkin     _In_ FxIoQueue* pDestQueue,
16688a978a17SVictor Perevertkin     _In_ FxRequest* pRequest
16698a978a17SVictor Perevertkin     )
16708a978a17SVictor Perevertkin {
16718a978a17SVictor Perevertkin     NTSTATUS status;
16728a978a17SVictor Perevertkin     KIRQL irql;
16738a978a17SVictor Perevertkin 
16748a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
16758a978a17SVictor Perevertkin 
16768a978a17SVictor Perevertkin     pRequest->Lock(&irql);
16778a978a17SVictor Perevertkin 
16788a978a17SVictor Perevertkin     status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
16798a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
16808a978a17SVictor Perevertkin         status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
16818a978a17SVictor Perevertkin     }
16828a978a17SVictor Perevertkin 
16838a978a17SVictor Perevertkin     pRequest->Unlock(irql);
16848a978a17SVictor Perevertkin 
16858a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
16868a978a17SVictor Perevertkin         return status;
16878a978a17SVictor Perevertkin     }
16888a978a17SVictor Perevertkin 
16898a978a17SVictor Perevertkin     if (pDestQueue == this) {
16908a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
16918a978a17SVictor Perevertkin                             "Cannot forward a request to the same WDFQUEUE 0x%p"
16928a978a17SVictor Perevertkin                             " %!STATUS!",
16938a978a17SVictor Perevertkin                             GetObjectHandle(),
16948a978a17SVictor Perevertkin                             STATUS_INVALID_DEVICE_REQUEST);
16958a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(FxDriverGlobals);
16968a978a17SVictor Perevertkin         return STATUS_INVALID_DEVICE_REQUEST;
16978a978a17SVictor Perevertkin     }
16988a978a17SVictor Perevertkin 
16998a978a17SVictor Perevertkin     if ((m_Device != pDestQueue->m_Device)) {
17008a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
17018a978a17SVictor Perevertkin                             "Cannot forward a request to a different WDFDEVICE 0x%p",
17028a978a17SVictor Perevertkin                             pDestQueue->m_Device->GetHandle());
17038a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(FxDriverGlobals);
17048a978a17SVictor Perevertkin         return STATUS_INVALID_DEVICE_REQUEST;
17058a978a17SVictor Perevertkin     }
17068a978a17SVictor Perevertkin 
17078a978a17SVictor Perevertkin     return status;
17088a978a17SVictor Perevertkin }
17098a978a17SVictor Perevertkin 
17108a978a17SVictor Perevertkin _Must_inspect_result_
17118a978a17SVictor Perevertkin NTSTATUS
ForwardRequest(__in FxIoQueue * pDestQueue,__in FxRequest * pRequest)17128a978a17SVictor Perevertkin FxIoQueue::ForwardRequest(
17138a978a17SVictor Perevertkin     __in FxIoQueue* pDestQueue,
17148a978a17SVictor Perevertkin     __in FxRequest* pRequest
17158a978a17SVictor Perevertkin     )
17168a978a17SVictor Perevertkin /*++
17178a978a17SVictor Perevertkin 
17188a978a17SVictor Perevertkin Routine Description:
17198a978a17SVictor Perevertkin 
17208a978a17SVictor Perevertkin     ForwardRequest is called from the drivers EvtIoDefault routine
17218a978a17SVictor Perevertkin     and the following conditions apply:
17228a978a17SVictor Perevertkin 
17238a978a17SVictor Perevertkin     Request is not on a CSQ and not cancellable
17248a978a17SVictor Perevertkin 
17258a978a17SVictor Perevertkin     Request is FXREQUEST_FLAG_DRIVER_OWNED
17268a978a17SVictor Perevertkin 
17278a978a17SVictor Perevertkin     m_DriverIoCount has been incremented to reflect the request
17288a978a17SVictor Perevertkin 
17298a978a17SVictor Perevertkin     Request has an I/O completion callback function pointing to
17308a978a17SVictor Perevertkin     FxIoQueueRequestComplete with the context for this Queue
17318a978a17SVictor Perevertkin 
17328a978a17SVictor Perevertkin     The Request has one reference count from the I/O completion callback.
17338a978a17SVictor Perevertkin 
17348a978a17SVictor Perevertkin     If a driver calls this API, it will not complete the request
17358a978a17SVictor Perevertkin     as a result of this queues EvtIoDefault, and does not own
17368a978a17SVictor Perevertkin     the request until it has been re-presented by the Destination
17378a978a17SVictor Perevertkin     Queue.
17388a978a17SVictor Perevertkin 
17398a978a17SVictor Perevertkin Arguments:
17408a978a17SVictor Perevertkin 
17418a978a17SVictor Perevertkin Returns:
17428a978a17SVictor Perevertkin 
17438a978a17SVictor Perevertkin     NTSTATUS
17448a978a17SVictor Perevertkin 
17458a978a17SVictor Perevertkin --*/
17468a978a17SVictor Perevertkin {
17478a978a17SVictor Perevertkin     NTSTATUS status;
17488a978a17SVictor Perevertkin 
17498a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
17508a978a17SVictor Perevertkin 
17518a978a17SVictor Perevertkin     status = VerifyForwardRequest(FxDriverGlobals, pDestQueue, pRequest);
17528a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
17538a978a17SVictor Perevertkin         return status;
17548a978a17SVictor Perevertkin     }
17558a978a17SVictor Perevertkin 
17568a978a17SVictor Perevertkin     status = ForwardRequestWorker(pRequest, pDestQueue);
17578a978a17SVictor Perevertkin     return status;
17588a978a17SVictor Perevertkin }
17598a978a17SVictor Perevertkin 
17608a978a17SVictor Perevertkin _Must_inspect_result_
17618a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyQueueDriverCreatedRequest)17628a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyQueueDriverCreatedRequest) (
17638a978a17SVictor Perevertkin     _In_    PFX_DRIVER_GLOBALS FxDriverGlobals,
17648a978a17SVictor Perevertkin     _In_    FxRequest*  Request,
17658a978a17SVictor Perevertkin     _Inout_ SHORT*      OldFlags
17668a978a17SVictor Perevertkin     )
17678a978a17SVictor Perevertkin {
17688a978a17SVictor Perevertkin     NTSTATUS    status;
17698a978a17SVictor Perevertkin     KIRQL       irql;
17708a978a17SVictor Perevertkin 
17718a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
17728a978a17SVictor Perevertkin 
17738a978a17SVictor Perevertkin     Request->Lock(&irql);
17748a978a17SVictor Perevertkin 
17758a978a17SVictor Perevertkin     *OldFlags = Request->GetVerifierFlagsLocked();
17768a978a17SVictor Perevertkin     ASSERT((FXREQUEST_FLAG_DRIVER_DISPATCH & (*OldFlags)) == 0);
17778a978a17SVictor Perevertkin 
17788a978a17SVictor Perevertkin     status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals);
17798a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
17808a978a17SVictor Perevertkin         // Clear the driver owned flag.
17818a978a17SVictor Perevertkin         ASSERT((FXREQUEST_FLAG_DRIVER_OWNED & (*OldFlags)) != 0);
17828a978a17SVictor Perevertkin         Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
17838a978a17SVictor Perevertkin     }
17848a978a17SVictor Perevertkin 
17858a978a17SVictor Perevertkin     Request->Unlock(irql);
17868a978a17SVictor Perevertkin     return status;
17878a978a17SVictor Perevertkin }
17888a978a17SVictor Perevertkin 
17898a978a17SVictor Perevertkin _Must_inspect_result_
17908a978a17SVictor Perevertkin NTSTATUS
QueueDriverCreatedRequest(__in FxRequest * Request,__in BOOLEAN ParentQueue)17918a978a17SVictor Perevertkin FxIoQueue::QueueDriverCreatedRequest(
17928a978a17SVictor Perevertkin     __in FxRequest* Request,
17938a978a17SVictor Perevertkin     __in BOOLEAN    ParentQueue
17948a978a17SVictor Perevertkin     )
17958a978a17SVictor Perevertkin /*++
17968a978a17SVictor Perevertkin 
17978a978a17SVictor Perevertkin Routine Description:
17988a978a17SVictor Perevertkin 
17998a978a17SVictor Perevertkin     Insert a driver-created-request into this queue.
18008a978a17SVictor Perevertkin     The following conditions apply:
18018a978a17SVictor Perevertkin 
18028a978a17SVictor Perevertkin     Request is not on a CSQ and not cancellable.
18038a978a17SVictor Perevertkin 
18048a978a17SVictor Perevertkin     Request doesn't have the FXREQUEST_FLAG_DRIVER_OWNED set yet.
18058a978a17SVictor Perevertkin 
18068a978a17SVictor Perevertkin     Request doesn't have an I/O completion callback function pointing to
18078a978a17SVictor Perevertkin     FxIoQueueRequestComplete since the original queue is NULL.
18088a978a17SVictor Perevertkin 
18098a978a17SVictor Perevertkin     The Request has one reference count from WdfRequestCreate[FromIrp].
18108a978a17SVictor Perevertkin 
18118a978a17SVictor Perevertkin     On a successful return, the request is owned by the queue. Driver can complete
18128a978a17SVictor Perevertkin     this request only after it has been re-presented to the driver.
18138a978a17SVictor Perevertkin 
18148a978a17SVictor Perevertkin Arguments:
18158a978a17SVictor Perevertkin 
18168a978a17SVictor Perevertkin     Request - Driver created request (already validated by public API) to
18178a978a17SVictor Perevertkin                    insert in queue.
18188a978a17SVictor Perevertkin 
18198a978a17SVictor Perevertkin     ParentQueue - TRUE if the queue is owned by the parent device.
18208a978a17SVictor Perevertkin 
18218a978a17SVictor Perevertkin Returns:
18228a978a17SVictor Perevertkin 
18238a978a17SVictor Perevertkin     NTSTATUS
18248a978a17SVictor Perevertkin 
18258a978a17SVictor Perevertkin --*/
18268a978a17SVictor Perevertkin {
18278a978a17SVictor Perevertkin     NTSTATUS        status;
18288a978a17SVictor Perevertkin     CfxDeviceBase * origDeviceBase;
18298a978a17SVictor Perevertkin     SHORT           oldFlags = 0;
18308a978a17SVictor Perevertkin     FxIrp*          fxIrp;
18318a978a17SVictor Perevertkin 
18328a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS fxDriverGlobals = GetDriverGlobals();
18338a978a17SVictor Perevertkin     fxIrp = Request->GetFxIrp();
18348a978a17SVictor Perevertkin 
18358a978a17SVictor Perevertkin     status = VerifyQueueDriverCreatedRequest(fxDriverGlobals, Request, &oldFlags);
18368a978a17SVictor Perevertkin     if(!NT_SUCCESS(status)) {
18378a978a17SVictor Perevertkin         return status;
18388a978a17SVictor Perevertkin     }
18398a978a17SVictor Perevertkin 
18408a978a17SVictor Perevertkin     ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) ==
18418a978a17SVictor Perevertkin            FxRequestCompletionStateNone);
18428a978a17SVictor Perevertkin 
18438a978a17SVictor Perevertkin     //
18448a978a17SVictor Perevertkin     // If this is the parent queue, we need to adjust the IRP's stack.
18458a978a17SVictor Perevertkin     //
18468a978a17SVictor Perevertkin     if (ParentQueue) {
18478a978a17SVictor Perevertkin 
18488a978a17SVictor Perevertkin         //
18498a978a17SVictor Perevertkin         // IRP should not have a completion routine set yet.
18508a978a17SVictor Perevertkin         //
18518a978a17SVictor Perevertkin 
18528a978a17SVictor Perevertkin         ASSERT(fxIrp->GetNextCompletionRoutine() == NULL);
18538a978a17SVictor Perevertkin 
18548a978a17SVictor Perevertkin         fxIrp->CopyCurrentIrpStackLocationToNext();
18558a978a17SVictor Perevertkin         fxIrp->SetNextIrpStackLocation();
18568a978a17SVictor Perevertkin 
18578a978a17SVictor Perevertkin         //
18588a978a17SVictor Perevertkin         // Save a pointer to the device object for this request so that it can
18598a978a17SVictor Perevertkin         // be used later in completion.
18608a978a17SVictor Perevertkin         //
18618a978a17SVictor Perevertkin         fxIrp->SetCurrentDeviceObject(m_Device->GetDeviceObject());
18628a978a17SVictor Perevertkin     }
18638a978a17SVictor Perevertkin 
18648a978a17SVictor Perevertkin     origDeviceBase = Request->GetDeviceBase();
18658a978a17SVictor Perevertkin     Request->SetDeviceBase((CfxDeviceBase *)m_Device);
18668a978a17SVictor Perevertkin 
18678a978a17SVictor Perevertkin     //
18688a978a17SVictor Perevertkin     // Attempt to insert the request into the queue
18698a978a17SVictor Perevertkin     //
18708a978a17SVictor Perevertkin     status = QueueRequestFromForward(Request);
18718a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
18728a978a17SVictor Perevertkin         //
18738a978a17SVictor Perevertkin         // Request was not accepted, restore the original DeviceBase and flags.
18748a978a17SVictor Perevertkin         //
18758a978a17SVictor Perevertkin         ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) ==
18768a978a17SVictor Perevertkin                FxRequestCompletionStateNone);
18778a978a17SVictor Perevertkin 
18788a978a17SVictor Perevertkin         //
18798a978a17SVictor Perevertkin         // Restore original device/info.
18808a978a17SVictor Perevertkin         //
18818a978a17SVictor Perevertkin         Request->SetDeviceBase(origDeviceBase);
18828a978a17SVictor Perevertkin 
18838a978a17SVictor Perevertkin         if (fxDriverGlobals->FxVerifierOn) {
18848a978a17SVictor Perevertkin             Request->SetVerifierFlags(oldFlags);
18858a978a17SVictor Perevertkin         }
18868a978a17SVictor Perevertkin 
18878a978a17SVictor Perevertkin         //
18888a978a17SVictor Perevertkin         // If this is the parent queue, we need to adjust the IRP's stack.
18898a978a17SVictor Perevertkin         //
18908a978a17SVictor Perevertkin         if (ParentQueue) {
18918a978a17SVictor Perevertkin             fxIrp->SkipCurrentIrpStackLocation();
18928a978a17SVictor Perevertkin             //
18938a978a17SVictor Perevertkin             // There is no completion routine. See above assert.
18948a978a17SVictor Perevertkin             //
18958a978a17SVictor Perevertkin             Request->m_Irp.ClearNextStack();
18968a978a17SVictor Perevertkin         }
18978a978a17SVictor Perevertkin     }
18988a978a17SVictor Perevertkin 
18998a978a17SVictor Perevertkin     return status;
19008a978a17SVictor Perevertkin }
19018a978a17SVictor Perevertkin 
19028a978a17SVictor Perevertkin _Must_inspect_result_
19038a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyRequeue)19048a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyRequeue) (
19058a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
19068a978a17SVictor Perevertkin     _In_ FxRequest* pRequest
19078a978a17SVictor Perevertkin     )
19088a978a17SVictor Perevertkin {
19098a978a17SVictor Perevertkin     NTSTATUS status = STATUS_SUCCESS;
19108a978a17SVictor Perevertkin     KIRQL irql;
19118a978a17SVictor Perevertkin 
19128a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
19138a978a17SVictor Perevertkin 
19148a978a17SVictor Perevertkin     pRequest->Lock(&irql);
19158a978a17SVictor Perevertkin 
19168a978a17SVictor Perevertkin     status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
19178a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
19188a978a17SVictor Perevertkin         status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
19198a978a17SVictor Perevertkin     }
19208a978a17SVictor Perevertkin 
19218a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
19228a978a17SVictor Perevertkin         pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED |
19238a978a17SVictor Perevertkin                                            FXREQUEST_FLAG_DRIVER_DISPATCH);
19248a978a17SVictor Perevertkin     }
19258a978a17SVictor Perevertkin     pRequest->Unlock(irql);
19268a978a17SVictor Perevertkin 
19278a978a17SVictor Perevertkin     return status;
19288a978a17SVictor Perevertkin }
19298a978a17SVictor Perevertkin 
19308a978a17SVictor Perevertkin 
19318a978a17SVictor Perevertkin _Must_inspect_result_
19328a978a17SVictor Perevertkin NTSTATUS
Requeue(__in FxRequest * pRequest)19338a978a17SVictor Perevertkin FxIoQueue::Requeue(
19348a978a17SVictor Perevertkin     __in FxRequest* pRequest
19358a978a17SVictor Perevertkin     )
19368a978a17SVictor Perevertkin {
19378a978a17SVictor Perevertkin     NTSTATUS status;
19388a978a17SVictor Perevertkin     FxRequestCompletionState oldState;
19398a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
19408a978a17SVictor Perevertkin     KIRQL irql;
19418a978a17SVictor Perevertkin 
19428a978a17SVictor Perevertkin     status = VerifyRequeue(FxDriverGlobals, pRequest);
19438a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
19448a978a17SVictor Perevertkin         return status;
19458a978a17SVictor Perevertkin     }
19468a978a17SVictor Perevertkin 
19478a978a17SVictor Perevertkin     //
19488a978a17SVictor Perevertkin     // Requeue is allowed only on Manual queue.
19498a978a17SVictor Perevertkin     //
19508a978a17SVictor Perevertkin     if(pRequest->GetCurrentQueue()->m_Type !=  WdfIoQueueDispatchManual) {
19518a978a17SVictor Perevertkin 
19528a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
19538a978a17SVictor Perevertkin                                 "Requeue is allowed only for "
19548a978a17SVictor Perevertkin                                 "a manual queue, WDFREQUEST 0x%p "
19558a978a17SVictor Perevertkin                                 "%!STATUS!",
19568a978a17SVictor Perevertkin                                 pRequest,
19578a978a17SVictor Perevertkin                                 STATUS_INVALID_DEVICE_REQUEST);
19588a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(FxDriverGlobals);
19598a978a17SVictor Perevertkin             return STATUS_INVALID_DEVICE_REQUEST;
19608a978a17SVictor Perevertkin     }
19618a978a17SVictor Perevertkin 
19628a978a17SVictor Perevertkin     //
19638a978a17SVictor Perevertkin     // The request has only one reference, held by the completion
19648a978a17SVictor Perevertkin     // callback function. We need to take another one before cancelling
19658a978a17SVictor Perevertkin     // this function, otherwise we will lose the request object
19668a978a17SVictor Perevertkin     //
19678a978a17SVictor Perevertkin     pRequest->ADDREF(FXREQUEST_STATE_TAG);
19688a978a17SVictor Perevertkin 
19698a978a17SVictor Perevertkin     // Cancel the request complete callback (deletes a reference)
19708a978a17SVictor Perevertkin     oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone);
19718a978a17SVictor Perevertkin     ASSERT(oldState == FxRequestCompletionStateQueue);
19728a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(oldState);
19738a978a17SVictor Perevertkin 
19748a978a17SVictor Perevertkin     Lock(&irql);
19758a978a17SVictor Perevertkin 
19768a978a17SVictor Perevertkin     //
19778a978a17SVictor Perevertkin     // We are going to place the request back on the queue
19788a978a17SVictor Perevertkin     //
19798a978a17SVictor Perevertkin 
19808a978a17SVictor Perevertkin 
19818a978a17SVictor Perevertkin     // Driver did not accept the I/O
19828a978a17SVictor Perevertkin     RemoveFromDriverOwnedList(pRequest);
19838a978a17SVictor Perevertkin 
19848a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
19858a978a17SVictor Perevertkin                         "WDFREQUEST 0x%p", pRequest->GetHandle());
19868a978a17SVictor Perevertkin 
19878a978a17SVictor Perevertkin     //
19888a978a17SVictor Perevertkin     // Check if we need to delete this request.
19898a978a17SVictor Perevertkin     //
19908a978a17SVictor Perevertkin     if (m_CancelDispatchedRequests) {
19918a978a17SVictor Perevertkin         //
19928a978a17SVictor Perevertkin         // Do not requeue this request.
19938a978a17SVictor Perevertkin         //
19948a978a17SVictor Perevertkin         status = STATUS_CANCELLED;
19958a978a17SVictor Perevertkin     }
19968a978a17SVictor Perevertkin     else {
19978a978a17SVictor Perevertkin         //
19988a978a17SVictor Perevertkin         // Place the request back at the head of the main queue
19998a978a17SVictor Perevertkin         // so as not to re-order requests
20008a978a17SVictor Perevertkin         //
20018a978a17SVictor Perevertkin         status = pRequest->InsertHeadIrpQueue(&m_Queue, NULL);
20028a978a17SVictor Perevertkin     }
20038a978a17SVictor Perevertkin 
20048a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
20058a978a17SVictor Perevertkin 
20068a978a17SVictor Perevertkin         // Request did not get placed in queue
20078a978a17SVictor Perevertkin         ASSERT(status == STATUS_CANCELLED);
20088a978a17SVictor Perevertkin         //
20098a978a17SVictor Perevertkin         // Let the caller think the request is requeued successfully
20108a978a17SVictor Perevertkin         // because this is no different from the request cancelling
20118a978a17SVictor Perevertkin         // while it's in the queue. By returning STATUS_CANCELLED
20128a978a17SVictor Perevertkin         // the caller can't take any recovery action anyways
20138a978a17SVictor Perevertkin         // because the request is gone.
20148a978a17SVictor Perevertkin         //
20158a978a17SVictor Perevertkin         status = STATUS_SUCCESS;
20168a978a17SVictor Perevertkin 
20178a978a17SVictor Perevertkin         //
20188a978a17SVictor Perevertkin         // We must add a reference since the CancelForQueue path
20198a978a17SVictor Perevertkin         // assumes we were on the FxIrpQueue with the extra reference
20208a978a17SVictor Perevertkin         //
20218a978a17SVictor Perevertkin         pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
20228a978a17SVictor Perevertkin 
20238a978a17SVictor Perevertkin         //
20248a978a17SVictor Perevertkin         // Mark the request as cancelled, place it on the cancel list,
20258a978a17SVictor Perevertkin         // and schedule the cancel event to the driver
20268a978a17SVictor Perevertkin         //
20278a978a17SVictor Perevertkin         CancelForQueue(pRequest, irql);
20288a978a17SVictor Perevertkin 
20298a978a17SVictor Perevertkin         Lock(&irql);
20308a978a17SVictor Perevertkin     }
20318a978a17SVictor Perevertkin     else {
20328a978a17SVictor Perevertkin         // Check if went from no requests to have requests
20338a978a17SVictor Perevertkin         CheckTransitionFromEmpty();
20348a978a17SVictor Perevertkin     }
20358a978a17SVictor Perevertkin 
20368a978a17SVictor Perevertkin     //
20378a978a17SVictor Perevertkin     // Visit the DispatchEvent so that we can deliver EvtIoReadyNotify
20388a978a17SVictor Perevertkin     //
20398a978a17SVictor Perevertkin     DispatchEvents(irql);
20408a978a17SVictor Perevertkin 
20418a978a17SVictor Perevertkin     return status;
20428a978a17SVictor Perevertkin }
20438a978a17SVictor Perevertkin 
20448a978a17SVictor Perevertkin _Must_inspect_result_
20458a978a17SVictor Perevertkin NTSTATUS
FX_VF_METHOD(FxIoQueue,VerifyRequestCancelable)20468a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyRequestCancelable) (
20478a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
20488a978a17SVictor Perevertkin     _In_ FxRequest* pRequest,
20498a978a17SVictor Perevertkin     _In_ BOOLEAN Cancelable
20508a978a17SVictor Perevertkin     )
20518a978a17SVictor Perevertkin {
20528a978a17SVictor Perevertkin     NTSTATUS status;
20538a978a17SVictor Perevertkin     KIRQL irql;
20548a978a17SVictor Perevertkin 
20558a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
20568a978a17SVictor Perevertkin 
20578a978a17SVictor Perevertkin     pRequest->Lock(&irql);
20588a978a17SVictor Perevertkin 
20598a978a17SVictor Perevertkin     // Make sure the driver owns the request
20608a978a17SVictor Perevertkin     status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
20618a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
20628a978a17SVictor Perevertkin         goto Done;
20638a978a17SVictor Perevertkin     }
20648a978a17SVictor Perevertkin 
20658a978a17SVictor Perevertkin     if (Cancelable) {
20668a978a17SVictor Perevertkin         //
20678a978a17SVictor Perevertkin         // Make sure the request is not cancelable for it to be made
20688a978a17SVictor Perevertkin         // cancelable.
20698a978a17SVictor Perevertkin         //
20708a978a17SVictor Perevertkin         status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
20718a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
20728a978a17SVictor Perevertkin             goto Done;
20738a978a17SVictor Perevertkin         }
20748a978a17SVictor Perevertkin     }
20758a978a17SVictor Perevertkin     else {
20768a978a17SVictor Perevertkin         //
20778a978a17SVictor Perevertkin         // Make sure the request is cancelable for it to be made
20788a978a17SVictor Perevertkin         // uncancelable.
20798a978a17SVictor Perevertkin         //
20808a978a17SVictor Perevertkin         status = pRequest->VerifyRequestIsCancelable(FxDriverGlobals);
20818a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
20828a978a17SVictor Perevertkin             goto Done;
20838a978a17SVictor Perevertkin         }
20848a978a17SVictor Perevertkin     }
20858a978a17SVictor Perevertkin 
20868a978a17SVictor Perevertkin Done:
20878a978a17SVictor Perevertkin     pRequest->Unlock(irql);
20888a978a17SVictor Perevertkin     return status;
20898a978a17SVictor Perevertkin }
20908a978a17SVictor Perevertkin 
20918a978a17SVictor Perevertkin _Must_inspect_result_
20928a978a17SVictor Perevertkin NTSTATUS
RequestCancelable(__in FxRequest * pRequest,__in BOOLEAN Cancelable,__in_opt PFN_WDF_REQUEST_CANCEL EvtRequestCancel,__in BOOLEAN FailIfIrpIsCancelled)20938a978a17SVictor Perevertkin FxIoQueue::RequestCancelable(
20948a978a17SVictor Perevertkin     __in FxRequest* pRequest,
20958a978a17SVictor Perevertkin     __in BOOLEAN    Cancelable,
20968a978a17SVictor Perevertkin     __in_opt PFN_WDF_REQUEST_CANCEL  EvtRequestCancel,
20978a978a17SVictor Perevertkin     __in BOOLEAN    FailIfIrpIsCancelled
20988a978a17SVictor Perevertkin    )
20998a978a17SVictor Perevertkin /*++
21008a978a17SVictor Perevertkin 
21018a978a17SVictor Perevertkin     Routine Description:
21028a978a17SVictor Perevertkin 
21038a978a17SVictor Perevertkin         This is called to mark or unmark the request cancelable.
21048a978a17SVictor Perevertkin 
21058a978a17SVictor Perevertkin     Arguments:
21068a978a17SVictor Perevertkin 
21078a978a17SVictor Perevertkin         FxRequest* - Request that is completing
21088a978a17SVictor Perevertkin 
21098a978a17SVictor Perevertkin         Cancelable - if TRUE, mark the request cancellable
21108a978a17SVictor Perevertkin                      if FALSE, mark the request not cancelable
21118a978a17SVictor Perevertkin                         if it's previously marked canceelable.
21128a978a17SVictor Perevertkin 
21138a978a17SVictor Perevertkin         EvtRequestCancel - points to driver provided cancel routine
21148a978a17SVictor Perevertkin                               if the cancelable flag is TRUE.
21158a978a17SVictor Perevertkin 
21168a978a17SVictor Perevertkin         FailIfIrpIsCancelled - if FALSE and the IRP is already cancelled,
21178a978a17SVictor Perevertkin                                   call the provided cancel routine and
21188a978a17SVictor Perevertkin                                   return success.
21198a978a17SVictor Perevertkin                                if TRUE and the IRP is already cancelled,
21208a978a17SVictor Perevertkin                                   return STATUS_CANCELLED.
21218a978a17SVictor Perevertkin 
21228a978a17SVictor Perevertkin     Returns:
21238a978a17SVictor Perevertkin 
21248a978a17SVictor Perevertkin         NTSTATUS
21258a978a17SVictor Perevertkin 
21268a978a17SVictor Perevertkin --*/
21278a978a17SVictor Perevertkin {
21288a978a17SVictor Perevertkin     NTSTATUS status;
21298a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
21308a978a17SVictor Perevertkin     KIRQL irql;
21318a978a17SVictor Perevertkin 
21328a978a17SVictor Perevertkin     status = VerifyRequestCancelable(FxDriverGlobals, pRequest, Cancelable);
21338a978a17SVictor Perevertkin     if(!NT_SUCCESS(status)) {
21348a978a17SVictor Perevertkin         return status;
21358a978a17SVictor Perevertkin     }
21368a978a17SVictor Perevertkin 
21378a978a17SVictor Perevertkin     if (Cancelable) {
21388a978a17SVictor Perevertkin 
21398a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
21408a978a17SVictor Perevertkin             pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
21418a978a17SVictor Perevertkin         }
21428a978a17SVictor Perevertkin         //
21438a978a17SVictor Perevertkin         // Set the Request for cancel status by inserting in the driver owned
21448a978a17SVictor Perevertkin         // CSQ. Note: This could fire the cancel callback right away
21458a978a17SVictor Perevertkin         // if the IRP was already cancelled.
21468a978a17SVictor Perevertkin         //
21478a978a17SVictor Perevertkin 
21488a978a17SVictor Perevertkin         ASSERT(EvtRequestCancel);
21498a978a17SVictor Perevertkin 
21508a978a17SVictor Perevertkin         Lock(&irql);
21518a978a17SVictor Perevertkin 
21528a978a17SVictor Perevertkin         pRequest->m_CancelRoutine.m_Cancel = EvtRequestCancel;
21538a978a17SVictor Perevertkin 
21548a978a17SVictor Perevertkin         //
21558a978a17SVictor Perevertkin         // Check if we need to delete this request.
21568a978a17SVictor Perevertkin         //
21578a978a17SVictor Perevertkin         if (m_CancelDispatchedRequests) {
21588a978a17SVictor Perevertkin             //
21598a978a17SVictor Perevertkin             // Purge is in progress, cancel this request.
21608a978a17SVictor Perevertkin             //
21618a978a17SVictor Perevertkin             status = STATUS_CANCELLED;
21628a978a17SVictor Perevertkin         }
21638a978a17SVictor Perevertkin         else {
21648a978a17SVictor Perevertkin             status = pRequest->InsertTailIrpQueue(&m_DriverCancelable, NULL);
21658a978a17SVictor Perevertkin         }
21668a978a17SVictor Perevertkin 
21678a978a17SVictor Perevertkin         if (NT_SUCCESS(status)) {
21688a978a17SVictor Perevertkin             Unlock(irql);
21698a978a17SVictor Perevertkin         }
21708a978a17SVictor Perevertkin         else if (FailIfIrpIsCancelled == FALSE) {
21718a978a17SVictor Perevertkin 
21728a978a17SVictor Perevertkin             ASSERT(status == STATUS_CANCELLED);
21738a978a17SVictor Perevertkin 
21748a978a17SVictor Perevertkin             // This is not an error to the driver
21758a978a17SVictor Perevertkin             status = STATUS_SUCCESS;
21768a978a17SVictor Perevertkin 
21778a978a17SVictor Perevertkin             pRequest->m_Canceled = TRUE;
21788a978a17SVictor Perevertkin 
21798a978a17SVictor Perevertkin             Unlock(irql);
21808a978a17SVictor Perevertkin 
21818a978a17SVictor Perevertkin             //
21828a978a17SVictor Perevertkin             // We must add a reference since the CancelForDriver path
21838a978a17SVictor Perevertkin             // assumes we were on the FxIrpQueue with the extra reference
21848a978a17SVictor Perevertkin             //
21858a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
21868a978a17SVictor Perevertkin 
21878a978a17SVictor Perevertkin             //
21888a978a17SVictor Perevertkin             // Mark the request as cancelled, place it on the cancel list,
21898a978a17SVictor Perevertkin             // and schedule the cancel event to the driver
21908a978a17SVictor Perevertkin             //
21918a978a17SVictor Perevertkin             CancelForDriver(pRequest);
21928a978a17SVictor Perevertkin         }
21938a978a17SVictor Perevertkin         else {
21948a978a17SVictor Perevertkin 
21958a978a17SVictor Perevertkin             ASSERT(status == STATUS_CANCELLED);
21968a978a17SVictor Perevertkin 
21978a978a17SVictor Perevertkin             pRequest->m_CancelRoutine.m_Cancel = NULL;
21988a978a17SVictor Perevertkin 
21998a978a17SVictor Perevertkin             //
22008a978a17SVictor Perevertkin             // Let the caller complete the request with STATUS_CANCELLED.
22018a978a17SVictor Perevertkin             //
22028a978a17SVictor Perevertkin             Unlock(irql);
22038a978a17SVictor Perevertkin 
22048a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
22058a978a17SVictor Perevertkin                 pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
22068a978a17SVictor Perevertkin             }
22078a978a17SVictor Perevertkin         }
22088a978a17SVictor Perevertkin 
22098a978a17SVictor Perevertkin         return status;
22108a978a17SVictor Perevertkin     }
22118a978a17SVictor Perevertkin     else {
22128a978a17SVictor Perevertkin         //
22138a978a17SVictor Perevertkin         // This can return STATUS_CANCELLED if the request
22148a978a17SVictor Perevertkin         // has been canceled already
22158a978a17SVictor Perevertkin         //
22168a978a17SVictor Perevertkin         Lock(&irql);
22178a978a17SVictor Perevertkin         status = pRequest->RemoveFromIrpQueue(&m_DriverCancelable);
22188a978a17SVictor Perevertkin 
22198a978a17SVictor Perevertkin         if (NT_SUCCESS(status)) {
22208a978a17SVictor Perevertkin             pRequest->m_CancelRoutine.m_Cancel = NULL;
22218a978a17SVictor Perevertkin         }
22228a978a17SVictor Perevertkin         else {
22238a978a17SVictor Perevertkin             //
22248a978a17SVictor Perevertkin             // In the failure case, the cancel routine has won the race and will
22258a978a17SVictor Perevertkin             // be invoked on another thread.
22268a978a17SVictor Perevertkin             //
22278a978a17SVictor Perevertkin             DO_NOTHING();
22288a978a17SVictor Perevertkin         }
22298a978a17SVictor Perevertkin         Unlock(irql);
22308a978a17SVictor Perevertkin 
22318a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
22328a978a17SVictor Perevertkin 
22338a978a17SVictor Perevertkin             // We got the request back, can clear the cancelable flag
22348a978a17SVictor Perevertkin             if (NT_SUCCESS(status)) {
22358a978a17SVictor Perevertkin                 pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
22368a978a17SVictor Perevertkin             }
22378a978a17SVictor Perevertkin         }
22388a978a17SVictor Perevertkin 
22398a978a17SVictor Perevertkin         return status;
22408a978a17SVictor Perevertkin     }
22418a978a17SVictor Perevertkin }
22428a978a17SVictor Perevertkin 
22438a978a17SVictor Perevertkin _Must_inspect_result_
22448a978a17SVictor Perevertkin NTSTATUS
QueueRequest(__in FxRequest * pRequest)22458a978a17SVictor Perevertkin FxIoQueue::QueueRequest(
22468a978a17SVictor Perevertkin     __in FxRequest* pRequest
22478a978a17SVictor Perevertkin     )
22488a978a17SVictor Perevertkin 
22498a978a17SVictor Perevertkin /*++
22508a978a17SVictor Perevertkin 
22518a978a17SVictor Perevertkin     Routine Description:
22528a978a17SVictor Perevertkin 
22538a978a17SVictor Perevertkin     Enqueue a request to the end of the queue.
22548a978a17SVictor Perevertkin 
22558a978a17SVictor Perevertkin     Note: This routine owns the final disposition of
22568a978a17SVictor Perevertkin           the Request object, and must handle it and
22578a978a17SVictor Perevertkin           dereference even if the driver does not.
22588a978a17SVictor Perevertkin 
22598a978a17SVictor Perevertkin     Arguments:
22608a978a17SVictor Perevertkin 
22618a978a17SVictor Perevertkin         pRequest - Pointer to Request object
22628a978a17SVictor Perevertkin 
22638a978a17SVictor Perevertkin     Returns:
22648a978a17SVictor Perevertkin 
22658a978a17SVictor Perevertkin         NTSTATUS
22668a978a17SVictor Perevertkin --*/
22678a978a17SVictor Perevertkin 
22688a978a17SVictor Perevertkin {
22698a978a17SVictor Perevertkin     NTSTATUS Status;
22708a978a17SVictor Perevertkin     KIRQL    irql;
22718a978a17SVictor Perevertkin     MdIrp    pIrp;
22728a978a17SVictor Perevertkin     FxIrp*   pFxIrp;
22738a978a17SVictor Perevertkin 
22748a978a17SVictor Perevertkin     // Get IoQueue Object Lock
22758a978a17SVictor Perevertkin     Lock(&irql);
22768a978a17SVictor Perevertkin 
22778a978a17SVictor Perevertkin     ASSERT(pRequest->GetRefCnt() == 1);
22788a978a17SVictor Perevertkin 
22798a978a17SVictor Perevertkin     //
22808a978a17SVictor Perevertkin     // If the request is reserved, take an additional reference. This reference
22818a978a17SVictor Perevertkin     // will be released when the request is completed. This additional reference
22828a978a17SVictor Perevertkin     // enables us to detect 2 to 1 transition in the completion path so that
22838a978a17SVictor Perevertkin     // we can reclaim the reserved request for reuse.
22848a978a17SVictor Perevertkin     //
22858a978a17SVictor Perevertkin     if (pRequest->IsReserved()) {
22868a978a17SVictor Perevertkin         pRequest->ADDREF(FXREQUEST_FWDPRG_TAG);
22878a978a17SVictor Perevertkin     }
22888a978a17SVictor Perevertkin 
22898a978a17SVictor Perevertkin     //
22908a978a17SVictor Perevertkin     // If queue is not taking new requests, fail now
22918a978a17SVictor Perevertkin     //
22928a978a17SVictor Perevertkin     if (!IsState(WdfIoQueueAcceptRequests)) {
22938a978a17SVictor Perevertkin 
22948a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
22958a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is not accepting requests, "
22968a978a17SVictor Perevertkin                             "state is %!WDF_IO_QUEUE_STATE!, %s"
22978a978a17SVictor Perevertkin                             "completing WDFREQUEST 0x%p %!STATUS!",
22988a978a17SVictor Perevertkin                             GetObjectHandle(), m_QueueState,
22998a978a17SVictor Perevertkin                             IsState(FxIoQueueShutdown) ?
23008a978a17SVictor Perevertkin                                 "power stopping (Drain) in progress," : "",
23018a978a17SVictor Perevertkin                             pRequest->GetHandle(),
23028a978a17SVictor Perevertkin                             STATUS_INVALID_DEVICE_STATE);
23038a978a17SVictor Perevertkin 
23048a978a17SVictor Perevertkin         // Must release IoQueue object Lock
23058a978a17SVictor Perevertkin         Unlock(irql);
23068a978a17SVictor Perevertkin 
23078a978a17SVictor Perevertkin         Status = STATUS_INVALID_DEVICE_STATE;
23088a978a17SVictor Perevertkin 
23098a978a17SVictor Perevertkin         // Complete it with error
23108a978a17SVictor Perevertkin         pRequest->CompleteWithInformation(Status, 0);
23118a978a17SVictor Perevertkin 
23128a978a17SVictor Perevertkin         // Dereference request object
23138a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
23148a978a17SVictor Perevertkin 
23158a978a17SVictor Perevertkin         return Status;
23168a978a17SVictor Perevertkin     }
23178a978a17SVictor Perevertkin 
23188a978a17SVictor Perevertkin     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
23198a978a17SVictor Perevertkin                         "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
23208a978a17SVictor Perevertkin                         pRequest->GetHandle(),GetObjectHandle());
23218a978a17SVictor Perevertkin 
23228a978a17SVictor Perevertkin     (VOID)pRequest->GetIrp(&pIrp);
23238a978a17SVictor Perevertkin 
23248a978a17SVictor Perevertkin     pFxIrp = pRequest->GetFxIrp();
23258a978a17SVictor Perevertkin 
23268a978a17SVictor Perevertkin     pFxIrp->MarkIrpPending();
23278a978a17SVictor Perevertkin 
23288a978a17SVictor Perevertkin     //
23298a978a17SVictor Perevertkin     // If the request is reserved, we may be called to dispatch
23308a978a17SVictor Perevertkin     // a pending reserved IRP from within the context of the completion routine.
23318a978a17SVictor Perevertkin     // So to avoid recursion, we will insert the request in the queue and try
23328a978a17SVictor Perevertkin     // to dispatch in the return path. If the request is not reserved then we
23338a978a17SVictor Perevertkin     // will dispatch it directly because this path is meant for dispatching new
23348a978a17SVictor Perevertkin     // incoming I/O. There is no concern for running into recursion in that
23358a978a17SVictor Perevertkin     // scenario.
23368a978a17SVictor Perevertkin     //
23378a978a17SVictor Perevertkin     if (pRequest->IsReserved() && m_Dispatching != 0) {
23388a978a17SVictor Perevertkin         InsertNewRequestLocked(&pRequest, irql);
23398a978a17SVictor Perevertkin         Unlock(irql);
23408a978a17SVictor Perevertkin     }
23418a978a17SVictor Perevertkin     else {
23428a978a17SVictor Perevertkin         DispatchEvents(irql, pRequest);
23438a978a17SVictor Perevertkin     }
23448a978a17SVictor Perevertkin 
23458a978a17SVictor Perevertkin     // We always return status pending through the frameworks
23468a978a17SVictor Perevertkin     return STATUS_PENDING;
23478a978a17SVictor Perevertkin }
23488a978a17SVictor Perevertkin 
23498a978a17SVictor Perevertkin _Must_inspect_result_
23508a978a17SVictor Perevertkin NTSTATUS
QueueRequestFromForward(__in FxRequest * pRequest)23518a978a17SVictor Perevertkin FxIoQueue::QueueRequestFromForward(
23528a978a17SVictor Perevertkin     __in FxRequest* pRequest
23538a978a17SVictor Perevertkin     )
23548a978a17SVictor Perevertkin 
23558a978a17SVictor Perevertkin /*++
23568a978a17SVictor Perevertkin 
23578a978a17SVictor Perevertkin     Routine Description:
23588a978a17SVictor Perevertkin 
23598a978a17SVictor Perevertkin     Enqueue a request to the end of the queue.
23608a978a17SVictor Perevertkin 
23618a978a17SVictor Perevertkin     This is an internal version that does not fail
23628a978a17SVictor Perevertkin     the request if it can not be enqueued.
23638a978a17SVictor Perevertkin 
23648a978a17SVictor Perevertkin     Arguments:
23658a978a17SVictor Perevertkin 
23668a978a17SVictor Perevertkin         pRequest - Pointer to Request object
23678a978a17SVictor Perevertkin 
23688a978a17SVictor Perevertkin     Returns:
23698a978a17SVictor Perevertkin 
23708a978a17SVictor Perevertkin         STATUS_SUCCESS on success
23718a978a17SVictor Perevertkin --*/
23728a978a17SVictor Perevertkin 
23738a978a17SVictor Perevertkin {
23748a978a17SVictor Perevertkin     NTSTATUS status;
23758a978a17SVictor Perevertkin     KIRQL    irql;
23768a978a17SVictor Perevertkin     BOOLEAN  fromIo;
23778a978a17SVictor Perevertkin 
23788a978a17SVictor Perevertkin     // Get IoQueue Object Lock
23798a978a17SVictor Perevertkin     Lock(&irql);
23808a978a17SVictor Perevertkin 
23818a978a17SVictor Perevertkin     //
23828a978a17SVictor Perevertkin     // If queue is not taking new requests, fail now
23838a978a17SVictor Perevertkin     //
23848a978a17SVictor Perevertkin     if (!IsState(WdfIoQueueAcceptRequests)) {
23858a978a17SVictor Perevertkin 
23868a978a17SVictor Perevertkin         status = STATUS_WDF_BUSY;
23878a978a17SVictor Perevertkin 
23888a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO,
23898a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is not accepting requests "
23908a978a17SVictor Perevertkin                             "state is %!WDF_IO_QUEUE_STATE!, %s"
23918a978a17SVictor Perevertkin                             "WDFREQUEST 0x%p %!STATUS!",
23928a978a17SVictor Perevertkin                             GetObjectHandle(), m_QueueState,
23938a978a17SVictor Perevertkin                             IsState(FxIoQueueShutdown) ?
23948a978a17SVictor Perevertkin                                 "power stopping (Drain) in progress," : "",
23958a978a17SVictor Perevertkin                             pRequest->GetHandle(), status);
23968a978a17SVictor Perevertkin 
23978a978a17SVictor Perevertkin         Unlock(irql);
23988a978a17SVictor Perevertkin 
23998a978a17SVictor Perevertkin         return status;
24008a978a17SVictor Perevertkin     }
24018a978a17SVictor Perevertkin #if FX_VERBOSE_TRACE
24028a978a17SVictor Perevertkin     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
24038a978a17SVictor Perevertkin                         "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
24048a978a17SVictor Perevertkin                         pRequest->GetHandle(), GetObjectHandle());
24058a978a17SVictor Perevertkin #endif
24068a978a17SVictor Perevertkin     //
24078a978a17SVictor Perevertkin     // The Request has one reference count, and no completion
24088a978a17SVictor Perevertkin     // callback function. It has been completely removed from
24098a978a17SVictor Perevertkin     // its previous queue.
24108a978a17SVictor Perevertkin     //
24118a978a17SVictor Perevertkin 
24128a978a17SVictor Perevertkin     //
24138a978a17SVictor Perevertkin     // Cache this info b/c the request can be delete and freed by the time we use it.
24148a978a17SVictor Perevertkin     //
24158a978a17SVictor Perevertkin     fromIo = pRequest->IsAllocatedFromIo();
24168a978a17SVictor Perevertkin 
24178a978a17SVictor Perevertkin     //
24188a978a17SVictor Perevertkin     // Insert it in the Cancel Safe Queue
24198a978a17SVictor Perevertkin     //
24208a978a17SVictor Perevertkin     // This will mark the IRP pending
24218a978a17SVictor Perevertkin     //
24228a978a17SVictor Perevertkin     status = pRequest->InsertTailIrpQueue(&m_Queue, NULL);
24238a978a17SVictor Perevertkin 
24248a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
24258a978a17SVictor Perevertkin 
24268a978a17SVictor Perevertkin         pRequest->SetCurrentQueue(this);
24278a978a17SVictor Perevertkin 
24288a978a17SVictor Perevertkin         ASSERT(status == STATUS_CANCELLED);
24298a978a17SVictor Perevertkin 
24308a978a17SVictor Perevertkin         //
24318a978a17SVictor Perevertkin         // We must add a reference since the CancelForQueue path
24328a978a17SVictor Perevertkin         // assumes we were on the FxIrpQueue with the extra reference
24338a978a17SVictor Perevertkin         //
24348a978a17SVictor Perevertkin         pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
24358a978a17SVictor Perevertkin 
24368a978a17SVictor Perevertkin         //
24378a978a17SVictor Perevertkin         // Mark the request as cancelled, place it on the cancel list,
24388a978a17SVictor Perevertkin         // and schedule the cancel event to the driver
24398a978a17SVictor Perevertkin         //
24408a978a17SVictor Perevertkin         CancelForQueue(pRequest, irql);
24418a978a17SVictor Perevertkin 
24428a978a17SVictor Perevertkin         Lock(&irql);
24438a978a17SVictor Perevertkin     }
24448a978a17SVictor Perevertkin     else {
24458a978a17SVictor Perevertkin         pRequest->SetCurrentQueue(this);
24468a978a17SVictor Perevertkin 
24478a978a17SVictor Perevertkin         // Check if went from no requests to have requests
24488a978a17SVictor Perevertkin         CheckTransitionFromEmpty();
24498a978a17SVictor Perevertkin     }
24508a978a17SVictor Perevertkin 
24518a978a17SVictor Perevertkin     //
24528a978a17SVictor Perevertkin     // If the request is driver-created, we may be called to dispatch
24538a978a17SVictor Perevertkin     // a request from within the context of the completion routine.
24548a978a17SVictor Perevertkin     // So to avoid recursion, we will try to dispatch in the return path.
24558a978a17SVictor Perevertkin     // If the request is not driver-created then we will dispatch it directly because
24568a978a17SVictor Perevertkin     // this path is meant for dispatching new incoming I/O. There is no concern for
24578a978a17SVictor Perevertkin     // running into recursion in that scenario.
24588a978a17SVictor Perevertkin     //
24598a978a17SVictor Perevertkin     if (fromIo == FALSE && m_Dispatching != 0) {
24608a978a17SVictor Perevertkin         Unlock(irql);
24618a978a17SVictor Perevertkin     }
24628a978a17SVictor Perevertkin     else {
24638a978a17SVictor Perevertkin         //
24648a978a17SVictor Perevertkin         // Attempt to dispatch any new requests.
24658a978a17SVictor Perevertkin         //
24668a978a17SVictor Perevertkin         // This releases, and re-acquires the IoQueue lock
24678a978a17SVictor Perevertkin         //
24688a978a17SVictor Perevertkin         DispatchEvents(irql);
24698a978a17SVictor Perevertkin     }
24708a978a17SVictor Perevertkin 
24718a978a17SVictor Perevertkin     return STATUS_SUCCESS;
24728a978a17SVictor Perevertkin }
24738a978a17SVictor Perevertkin 
24748a978a17SVictor Perevertkin VOID
DeferredDispatchRequestsFromDpc()24758a978a17SVictor Perevertkin FxIoQueue::DeferredDispatchRequestsFromDpc(
24768a978a17SVictor Perevertkin     )
24778a978a17SVictor Perevertkin 
24788a978a17SVictor Perevertkin /*++
24798a978a17SVictor Perevertkin 
24808a978a17SVictor Perevertkin     Routine Description:
24818a978a17SVictor Perevertkin 
24828a978a17SVictor Perevertkin     Dispatch requests from the queue to the driver
24838a978a17SVictor Perevertkin     from within the m_Dpc
24848a978a17SVictor Perevertkin 
24858a978a17SVictor Perevertkin     Arguments:
24868a978a17SVictor Perevertkin 
24878a978a17SVictor Perevertkin     Returns:
24888a978a17SVictor Perevertkin 
24898a978a17SVictor Perevertkin --*/
24908a978a17SVictor Perevertkin 
24918a978a17SVictor Perevertkin {
24928a978a17SVictor Perevertkin     KIRQL irql;
24938a978a17SVictor Perevertkin 
24948a978a17SVictor Perevertkin     Lock(&irql);
24958a978a17SVictor Perevertkin 
24968a978a17SVictor Perevertkin     ASSERT(m_DpcQueued != FALSE);
24978a978a17SVictor Perevertkin 
24988a978a17SVictor Perevertkin     m_RequeueDeferredDispatcher = FALSE;
24998a978a17SVictor Perevertkin 
25008a978a17SVictor Perevertkin     DispatchEvents(irql);
25018a978a17SVictor Perevertkin 
25028a978a17SVictor Perevertkin     //
25038a978a17SVictor Perevertkin     // DispatchEvents drops the lock before returning. So reacquire the lock.
25048a978a17SVictor Perevertkin     //
25058a978a17SVictor Perevertkin     Lock(&irql);
25068a978a17SVictor Perevertkin 
25078a978a17SVictor Perevertkin     if (m_Deleted == FALSE && m_RequeueDeferredDispatcher) {
25088a978a17SVictor Perevertkin         InsertQueueDpc();
25098a978a17SVictor Perevertkin     } else {
25108a978a17SVictor Perevertkin         m_RequeueDeferredDispatcher = FALSE;
25118a978a17SVictor Perevertkin         m_DpcQueued = FALSE;
25128a978a17SVictor Perevertkin     }
25138a978a17SVictor Perevertkin 
25148a978a17SVictor Perevertkin     Unlock(irql);
25158a978a17SVictor Perevertkin 
25168a978a17SVictor Perevertkin     return;
25178a978a17SVictor Perevertkin }
25188a978a17SVictor Perevertkin 
25198a978a17SVictor Perevertkin VOID
DeferredDispatchRequestsFromWorkerThread()25208a978a17SVictor Perevertkin FxIoQueue::DeferredDispatchRequestsFromWorkerThread(
25218a978a17SVictor Perevertkin     )
25228a978a17SVictor Perevertkin 
25238a978a17SVictor Perevertkin /*++
25248a978a17SVictor Perevertkin 
25258a978a17SVictor Perevertkin     Routine Description:
25268a978a17SVictor Perevertkin 
25278a978a17SVictor Perevertkin     Dispatch requests from the queue to the driver
25288a978a17SVictor Perevertkin     from within the m_WorkItem.
25298a978a17SVictor Perevertkin 
25308a978a17SVictor Perevertkin     Arguments:
25318a978a17SVictor Perevertkin 
25328a978a17SVictor Perevertkin     Returns:
25338a978a17SVictor Perevertkin 
25348a978a17SVictor Perevertkin --*/
25358a978a17SVictor Perevertkin 
25368a978a17SVictor Perevertkin {
25378a978a17SVictor Perevertkin     KIRQL irql;
25388a978a17SVictor Perevertkin 
25398a978a17SVictor Perevertkin     Lock(&irql);
25408a978a17SVictor Perevertkin 
25418a978a17SVictor Perevertkin     ASSERT(m_WorkItemQueued != FALSE);
25428a978a17SVictor Perevertkin 
25438a978a17SVictor Perevertkin     m_RequeueDeferredDispatcher = FALSE;
25448a978a17SVictor Perevertkin 
25458a978a17SVictor Perevertkin     DispatchEvents(irql);
25468a978a17SVictor Perevertkin 
25478a978a17SVictor Perevertkin     //
25488a978a17SVictor Perevertkin     // DispatchEvents drops the lock before returning. So reacquire
25498a978a17SVictor Perevertkin     // the lock.
25508a978a17SVictor Perevertkin     //
25518a978a17SVictor Perevertkin     Lock(&irql);
25528a978a17SVictor Perevertkin 
25538a978a17SVictor Perevertkin     if (m_Deleted == FALSE &&
25548a978a17SVictor Perevertkin         m_RequeueDeferredDispatcher &&
25558a978a17SVictor Perevertkin         m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) {
25568a978a17SVictor Perevertkin         //
25578a978a17SVictor Perevertkin         // Workitem is queued.
25588a978a17SVictor Perevertkin         //
25598a978a17SVictor Perevertkin         DO_NOTHING();
25608a978a17SVictor Perevertkin     } else {
25618a978a17SVictor Perevertkin         m_RequeueDeferredDispatcher = FALSE;
25628a978a17SVictor Perevertkin         m_WorkItemQueued = FALSE;
25638a978a17SVictor Perevertkin     }
25648a978a17SVictor Perevertkin 
25658a978a17SVictor Perevertkin     Unlock(irql);
25668a978a17SVictor Perevertkin 
25678a978a17SVictor Perevertkin     return;
25688a978a17SVictor Perevertkin }
25698a978a17SVictor Perevertkin 
25708a978a17SVictor Perevertkin NTSTATUS
InsertNewRequestLocked(__deref_in FxRequest ** Request,__in KIRQL PreviousIrql)25718a978a17SVictor Perevertkin FxIoQueue::InsertNewRequestLocked(
25728a978a17SVictor Perevertkin     __deref_in FxRequest** Request,
25738a978a17SVictor Perevertkin     __in KIRQL PreviousIrql
25748a978a17SVictor Perevertkin     )
25758a978a17SVictor Perevertkin /*++
25768a978a17SVictor Perevertkin 
25778a978a17SVictor Perevertkin     Routine Description:
25788a978a17SVictor Perevertkin 
25798a978a17SVictor Perevertkin     Purpose of this function is to insert the request that's dispatched
25808a978a17SVictor Perevertkin     by the IoPkg into FxIrpQueue. This function has been added to improve
25818a978a17SVictor Perevertkin     the performance of queueing logic. Prior to version 1.7, when a
25828a978a17SVictor Perevertkin     request is dispatched to a queue, it was first inserted into queue,
25838a978a17SVictor Perevertkin     various checks for the readiness of queue made, and then the request
25848a978a17SVictor Perevertkin     is removed from the queue to be presented to the driver.
25858a978a17SVictor Perevertkin 
25868a978a17SVictor Perevertkin     To improve the I/O performance, dispatching logic has been changed
25878a978a17SVictor Perevertkin     such that the request will not be inserted into the queue if the queue
25888a978a17SVictor Perevertkin     is ready to dispatch the request. If the queue is not ready or if there
25898a978a17SVictor Perevertkin     are other events to be dispatched before dispatching the new incoming request,
25908a978a17SVictor Perevertkin     we will queue the request first using this function before releasing the lock
25918a978a17SVictor Perevertkin     so that we don't change the ordering of requests in the queue.
25928a978a17SVictor Perevertkin 
25938a978a17SVictor Perevertkin --*/
25948a978a17SVictor Perevertkin {
25958a978a17SVictor Perevertkin     NTSTATUS status;
25968a978a17SVictor Perevertkin 
25978a978a17SVictor Perevertkin     status = (*Request)->InsertTailIrpQueue(&m_Queue, NULL);
25988a978a17SVictor Perevertkin 
25998a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
26008a978a17SVictor Perevertkin         //
26018a978a17SVictor Perevertkin         // Request was never presented to the driver
26028a978a17SVictor Perevertkin         // so there is no need to call CancelForQueue
26038a978a17SVictor Perevertkin         // in this case.
26048a978a17SVictor Perevertkin         //
26058a978a17SVictor Perevertkin         ASSERT(status == STATUS_CANCELLED);
26068a978a17SVictor Perevertkin 
26078a978a17SVictor Perevertkin         Unlock(PreviousIrql);
26088a978a17SVictor Perevertkin 
26098a978a17SVictor Perevertkin         (*Request)->CompleteWithInformation(status, 0);
26108a978a17SVictor Perevertkin 
26118a978a17SVictor Perevertkin         (*Request)->RELEASE(FXREQUEST_COMPLETE_TAG);
26128a978a17SVictor Perevertkin 
26138a978a17SVictor Perevertkin         Lock(&PreviousIrql);
26148a978a17SVictor Perevertkin     }
26158a978a17SVictor Perevertkin     else {
26168a978a17SVictor Perevertkin         (*Request)->SetCurrentQueue(this);
26178a978a17SVictor Perevertkin 
26188a978a17SVictor Perevertkin         // Check if went from no requests to have requests
26198a978a17SVictor Perevertkin         CheckTransitionFromEmpty();
26208a978a17SVictor Perevertkin     }
26218a978a17SVictor Perevertkin 
26228a978a17SVictor Perevertkin     //
26238a978a17SVictor Perevertkin     // Request is either inserted into the queue or completed. Clear
26248a978a17SVictor Perevertkin     // the field to prevent touching the request.
26258a978a17SVictor Perevertkin     //
26268a978a17SVictor Perevertkin     *Request = NULL;
26278a978a17SVictor Perevertkin 
26288a978a17SVictor Perevertkin     return status;
26298a978a17SVictor Perevertkin }
26308a978a17SVictor Perevertkin 
26318a978a17SVictor Perevertkin _Must_inspect_result_
26328a978a17SVictor Perevertkin BOOLEAN
CanThreadDispatchEventsLocked(__in KIRQL PreviousIrql)26338a978a17SVictor Perevertkin FxIoQueue::CanThreadDispatchEventsLocked(
26348a978a17SVictor Perevertkin     __in KIRQL PreviousIrql
26358a978a17SVictor Perevertkin     )
26368a978a17SVictor Perevertkin /*++
26378a978a17SVictor Perevertkin 
26388a978a17SVictor Perevertkin     Routine Description:
26398a978a17SVictor Perevertkin 
26408a978a17SVictor Perevertkin     Dispatch events and requests from the queue to the driver.
26418a978a17SVictor Perevertkin 
26428a978a17SVictor Perevertkin     The IoQueue object lock must be held on entry. This routine
26438a978a17SVictor Perevertkin     should not drop and reacquire the lock to ensure the request
26448a978a17SVictor Perevertkin     is not queued out of order.
26458a978a17SVictor Perevertkin 
26468a978a17SVictor Perevertkin     Returns:
26478a978a17SVictor Perevertkin 
26488a978a17SVictor Perevertkin         TRUE - if the thread meets all the sychronization and
26498a978a17SVictor Perevertkin                execution contraints to dispatch the events.
26508a978a17SVictor Perevertkin         FALSE - if the dispatching of events to be defered to
26518a978a17SVictor Perevertkin                another thread - either DPC or workitem.
26528a978a17SVictor Perevertkin --*/
26538a978a17SVictor Perevertkin {
26548a978a17SVictor Perevertkin     //
26558a978a17SVictor Perevertkin     // If the current irql is not at passive-level and the queue is configured
26568a978a17SVictor Perevertkin     // to receive events only at passive-level then we should queue a
26578a978a17SVictor Perevertkin     // workitem to defer the processing.
26588a978a17SVictor Perevertkin     //
26598a978a17SVictor Perevertkin     if ((PreviousIrql > PASSIVE_LEVEL) && m_PassiveLevel) {
26608a978a17SVictor Perevertkin         ASSERT(PreviousIrql <= DISPATCH_LEVEL);
26618a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO,
26628a978a17SVictor Perevertkin                             "Current thread 0x%p is not at the passive-level"
26638a978a17SVictor Perevertkin                             " %!irql!, posting to worker thread for WDFQUEUE"
26648a978a17SVictor Perevertkin                             " 0x%p",
26658a978a17SVictor Perevertkin                             Mx::MxGetCurrentThread(),
26668a978a17SVictor Perevertkin                             PreviousIrql,
26678a978a17SVictor Perevertkin                             GetObjectHandle());
26688a978a17SVictor Perevertkin         //
26698a978a17SVictor Perevertkin         // We only need to post this once
26708a978a17SVictor Perevertkin         //
26718a978a17SVictor Perevertkin         if (m_WorkItemQueued == FALSE) {
26728a978a17SVictor Perevertkin 
26738a978a17SVictor Perevertkin             m_WorkItemQueued = TRUE;
26748a978a17SVictor Perevertkin 
26758a978a17SVictor Perevertkin             if (!m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) {
26768a978a17SVictor Perevertkin                 ASSERT(FALSE);
26778a978a17SVictor Perevertkin                 m_WorkItemQueued = FALSE;
26788a978a17SVictor Perevertkin             }
26798a978a17SVictor Perevertkin         }
26808a978a17SVictor Perevertkin 
26818a978a17SVictor Perevertkin         return FALSE;
26828a978a17SVictor Perevertkin     }
26838a978a17SVictor Perevertkin 
26848a978a17SVictor Perevertkin     //
26858a978a17SVictor Perevertkin     // If the current thread is holding the presentation lock, we
26868a978a17SVictor Perevertkin     // must defer to a DPC or work item.
26878a978a17SVictor Perevertkin     // This is the result of the device driver calling
26888a978a17SVictor Perevertkin     // WdfRequestForwardToIoQueue, or WdfIoQueueStart/Stop from
26898a978a17SVictor Perevertkin     // within I/O dispatch handler. This can also occur if a driver
26908a978a17SVictor Perevertkin     // attempts to forward a request among a circular series of Queues
26918a978a17SVictor Perevertkin     // that are configured to have locking constraints.
26928a978a17SVictor Perevertkin     //
26938a978a17SVictor Perevertkin     if (m_CallbackLockPtr && m_CallbackLockPtr->IsOwner()) {
26948a978a17SVictor Perevertkin 
26958a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO,
26968a978a17SVictor Perevertkin                             "Presentation lock for WDFQUEUE 0x%p is "
26978a978a17SVictor Perevertkin                             "already held, deferring to dpc or workitem",
26988a978a17SVictor Perevertkin                             GetObjectHandle());
26998a978a17SVictor Perevertkin 
27008a978a17SVictor Perevertkin         if (m_PassiveLevel) {
27018a978a17SVictor Perevertkin 
27028a978a17SVictor Perevertkin             if(m_WorkItemQueued == FALSE) {
27038a978a17SVictor Perevertkin 
27048a978a17SVictor Perevertkin                 m_WorkItemQueued = TRUE;
27058a978a17SVictor Perevertkin 
27068a978a17SVictor Perevertkin                 if (!m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) {
27078a978a17SVictor Perevertkin                     ASSERT(FALSE);
27088a978a17SVictor Perevertkin                     m_WorkItemQueued = FALSE;
27098a978a17SVictor Perevertkin                 }
27108a978a17SVictor Perevertkin             }
27118a978a17SVictor Perevertkin         }
27128a978a17SVictor Perevertkin         else {
27138a978a17SVictor Perevertkin             //
27148a978a17SVictor Perevertkin             // We only need to post this once
27158a978a17SVictor Perevertkin             //
27168a978a17SVictor Perevertkin             if (m_DpcQueued == FALSE) {
27178a978a17SVictor Perevertkin 
27188a978a17SVictor Perevertkin                 m_DpcQueued = TRUE;
27198a978a17SVictor Perevertkin 
27208a978a17SVictor Perevertkin                 InsertQueueDpc();
27218a978a17SVictor Perevertkin             }
27228a978a17SVictor Perevertkin         }
27238a978a17SVictor Perevertkin 
27248a978a17SVictor Perevertkin         return FALSE;
27258a978a17SVictor Perevertkin     }
27268a978a17SVictor Perevertkin 
27278a978a17SVictor Perevertkin     return TRUE;
27288a978a17SVictor Perevertkin }
27298a978a17SVictor Perevertkin 
27308a978a17SVictor Perevertkin _Releases_lock_(this->m_SpinLock.m_Lock)
__drv_requiresIRQL(DISPATCH_LEVEL)27318a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
27328a978a17SVictor Perevertkin BOOLEAN
27338a978a17SVictor Perevertkin FxIoQueue::DispatchEvents(
27348a978a17SVictor Perevertkin     __in __drv_restoresIRQL KIRQL PreviousIrql,
27358a978a17SVictor Perevertkin     __in_opt FxRequest* NewRequest
27368a978a17SVictor Perevertkin     )
27378a978a17SVictor Perevertkin /*++
27388a978a17SVictor Perevertkin 
27398a978a17SVictor Perevertkin     Routine Description:
27408a978a17SVictor Perevertkin 
27418a978a17SVictor Perevertkin     Dispatch events and requests from the queue to the driver.
27428a978a17SVictor Perevertkin 
27438a978a17SVictor Perevertkin     The IoQueue object lock must be held on entry, but this routine can release
27448a978a17SVictor Perevertkin     and re-acquire the lock multiple times while processing.
27458a978a17SVictor Perevertkin 
27468a978a17SVictor Perevertkin     It returns to the caller with the lock released, but queue state may have
27478a978a17SVictor Perevertkin     changed.
27488a978a17SVictor Perevertkin 
27498a978a17SVictor Perevertkin     The main processing loop checks for various Queue state change events
27508a978a17SVictor Perevertkin     delivering them to the driver, and then finally any WDFREQUEST objects
27518a978a17SVictor Perevertkin     that are pending in the Queue.
27528a978a17SVictor Perevertkin 
27538a978a17SVictor Perevertkin     The design also handles the recursive case with the m_Dispatching
27548a978a17SVictor Perevertkin     field so that a driver that completes requests from within the
27558a978a17SVictor Perevertkin     callback does not cause a stack or lock recursion.
27568a978a17SVictor Perevertkin 
27578a978a17SVictor Perevertkin     All event callbacks to the device driver are provided though the
27588a978a17SVictor Perevertkin     FxCallback object which manages lock acquire and release as required
27598a978a17SVictor Perevertkin     by the locking model.
27608a978a17SVictor Perevertkin 
27618a978a17SVictor Perevertkin     In addition these may be passive or dispatch level locks.
27628a978a17SVictor Perevertkin     If configured for passive level callbacks,
27638a978a17SVictor Perevertkin     must defer to a work item if current thread is DISPATCH_LEVEL
27648a978a17SVictor Perevertkin     when not owning the current FxIoQueue lock
27658a978a17SVictor Perevertkin 
27668a978a17SVictor Perevertkin     Arguments:
27678a978a17SVictor Perevertkin 
27688a978a17SVictor Perevertkin     NewRequest - This is a new incoming request from the driver above.
27698a978a17SVictor Perevertkin                  It will be either presented to the driver or saved into
27708a978a17SVictor Perevertkin                  a queue if the conditions are not right to dispatch.
27718a978a17SVictor Perevertkin 
27728a978a17SVictor Perevertkin     Returns:
27738a978a17SVictor Perevertkin 
27748a978a17SVictor Perevertkin     FALSE if the queue is in a deleted state else TRUE.
27758a978a17SVictor Perevertkin     Caller should check for return value only if it's waiting
27768a978a17SVictor Perevertkin     on the some events to be invoked by this call.
27778a978a17SVictor Perevertkin 
27788a978a17SVictor Perevertkin --*/
27798a978a17SVictor Perevertkin {
27808a978a17SVictor Perevertkin     FxRequest*  pRequest;
27818a978a17SVictor Perevertkin     ULONG       totalIoCount;
27828a978a17SVictor Perevertkin     NTSTATUS    status;
27838a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
27848a978a17SVictor Perevertkin 
27858a978a17SVictor Perevertkin     if (m_Deleted) {
27868a978a17SVictor Perevertkin         ASSERT(NewRequest == NULL);
27878a978a17SVictor Perevertkin         Unlock(PreviousIrql);
27888a978a17SVictor Perevertkin         return FALSE;
27898a978a17SVictor Perevertkin     }
27908a978a17SVictor Perevertkin 
27918a978a17SVictor Perevertkin     //
27928a978a17SVictor Perevertkin     // The design of the I/O Queue allows all "events" to notify the driver of
27938a978a17SVictor Perevertkin     // to be deferred until the opportune time to deliver them.
27948a978a17SVictor Perevertkin     // Depending on the drivers configured locking and threading
27958a978a17SVictor Perevertkin     // mode, this may have to be deferred to a worker thread or a DPC
27968a978a17SVictor Perevertkin     // to be in a compatible IRQL level, or to prevent a lock recursion
27978a978a17SVictor Perevertkin     // when a parent objects lock is in effect.
27988a978a17SVictor Perevertkin     //
27998a978a17SVictor Perevertkin 
28008a978a17SVictor Perevertkin     if (CanThreadDispatchEventsLocked(PreviousIrql) == FALSE) {
28018a978a17SVictor Perevertkin         //
28028a978a17SVictor Perevertkin         // Previous workitem or Dpc might be running the DispatchEvents right now.
28038a978a17SVictor Perevertkin         // But it may be at a point where it might miss out to process the event
28048a978a17SVictor Perevertkin         // that we have been asked to dispatch. This is possible because the
28058a978a17SVictor Perevertkin         // DispatchEvent is reentrant as it acquires and drops lock along
28068a978a17SVictor Perevertkin         // the way. So we make a note of this, so that when the current Dpc or
28078a978a17SVictor Perevertkin         // workItem runs to completion, it will requeue itself to handle our message.
28088a978a17SVictor Perevertkin         //
28098a978a17SVictor Perevertkin         m_RequeueDeferredDispatcher = TRUE;
28108a978a17SVictor Perevertkin 
28118a978a17SVictor Perevertkin         //
28128a978a17SVictor Perevertkin         // Queue the request in to FxIrpQueue and return.
28138a978a17SVictor Perevertkin         //
28148a978a17SVictor Perevertkin         InsertNewRequest(&NewRequest, PreviousIrql);
28158a978a17SVictor Perevertkin         Unlock(PreviousIrql);
28168a978a17SVictor Perevertkin         return TRUE;
28178a978a17SVictor Perevertkin     }
28188a978a17SVictor Perevertkin 
28198a978a17SVictor Perevertkin     //
28208a978a17SVictor Perevertkin     // This must be incremented before attempting to deliver any
28218a978a17SVictor Perevertkin     // events to the driver. This prevents recursion on the presentation lock,
28228a978a17SVictor Perevertkin     // and limits the stack depth in a Start/Complete/Start/... recursion
28238a978a17SVictor Perevertkin     //
28248a978a17SVictor Perevertkin     m_Dispatching++;
28258a978a17SVictor Perevertkin 
28268a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
28278a978a17SVictor Perevertkin                         "Thread %p is processing WDFQUEUE 0x%p",
28288a978a17SVictor Perevertkin                         Mx::MxGetCurrentThread(), GetObjectHandle());
28298a978a17SVictor Perevertkin 
28308a978a17SVictor Perevertkin     //
28318a978a17SVictor Perevertkin     // At this point all constaints such as IRQL level, locks held,
28328a978a17SVictor Perevertkin     // and stack recursion protection has been satisfied, and we can
28338a978a17SVictor Perevertkin     // make callbacks into the device driver.
28348a978a17SVictor Perevertkin     //
28358a978a17SVictor Perevertkin     // Process events and requests until we either have an empty queue,
28368a978a17SVictor Perevertkin     // the driver stops taking requests, or some queue state does not
28378a978a17SVictor Perevertkin     // allow the driver to take new requests
28388a978a17SVictor Perevertkin     //
28398a978a17SVictor Perevertkin                                                   #pragma warning(disable:4127)
28408a978a17SVictor Perevertkin     while (TRUE) {
28418a978a17SVictor Perevertkin                                                   #pragma warning(default:4127)
28428a978a17SVictor Perevertkin         //
28438a978a17SVictor Perevertkin         // totoalIoCount is sum of requests pending in the queue and requests
28448a978a17SVictor Perevertkin         // currently owned by the driver.
28458a978a17SVictor Perevertkin         //
28468a978a17SVictor Perevertkin         totalIoCount = m_Queue.GetRequestCount() + m_DriverIoCount;
28478a978a17SVictor Perevertkin 
28488a978a17SVictor Perevertkin         //
28498a978a17SVictor Perevertkin         // Increment the count if there is a new request to be dispatched.
28508a978a17SVictor Perevertkin         //
28518a978a17SVictor Perevertkin         totalIoCount += ((NewRequest != NULL) ? 1 : 0);
28528a978a17SVictor Perevertkin 
28538a978a17SVictor Perevertkin         if (!IsListEmpty(&this->m_Cancelled)) {
28548a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
28558a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
28568a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
28578a978a17SVictor Perevertkin             }
28588a978a17SVictor Perevertkin 
28598a978a17SVictor Perevertkin             //
28608a978a17SVictor Perevertkin             // This can drop and re-acquire the queue lock
28618a978a17SVictor Perevertkin             // ProcessCancelledRequests returns FALSE if the queue is
28628a978a17SVictor Perevertkin             // notifying driver about power state changes.
28638a978a17SVictor Perevertkin             //
28648a978a17SVictor Perevertkin             if(ProcessCancelledRequests(&PreviousIrql)) {
28658a978a17SVictor Perevertkin                 continue;
28668a978a17SVictor Perevertkin             }
28678a978a17SVictor Perevertkin         }
28688a978a17SVictor Perevertkin 
28698a978a17SVictor Perevertkin         if (!IsListEmpty(&this->m_CanceledOnQueueList)) {
28708a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
28718a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
28728a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
28738a978a17SVictor Perevertkin             }
28748a978a17SVictor Perevertkin 
28758a978a17SVictor Perevertkin             //
28768a978a17SVictor Perevertkin             // This can drop and re-acquire the queue lock
28778a978a17SVictor Perevertkin             // ProcessCancelledRequests returns FALSE if the queue is
28788a978a17SVictor Perevertkin             // notifying driver about power state changes.
28798a978a17SVictor Perevertkin             //
28808a978a17SVictor Perevertkin             if (ProcessCancelledRequestsOnQueue(&PreviousIrql)) {
28818a978a17SVictor Perevertkin                 continue;
28828a978a17SVictor Perevertkin             }
28838a978a17SVictor Perevertkin         }
28848a978a17SVictor Perevertkin 
28858a978a17SVictor Perevertkin         if (m_IdleComplete.Method != NULL &&
28868a978a17SVictor Perevertkin             m_Dispatching == 1L &&
28878a978a17SVictor Perevertkin             m_DriverIoCount == 0L) {
28888a978a17SVictor Perevertkin 
28898a978a17SVictor Perevertkin             InsertNewRequest(&NewRequest, PreviousIrql);
28908a978a17SVictor Perevertkin 
28918a978a17SVictor Perevertkin             // no more driver owned requests, we can clear the following flag:
28928a978a17SVictor Perevertkin             m_CancelDispatchedRequests = FALSE;
28938a978a17SVictor Perevertkin 
28948a978a17SVictor Perevertkin             // This can drop and re-acquire the queue lock
28958a978a17SVictor Perevertkin             ProcessIdleComplete(&PreviousIrql);
28968a978a17SVictor Perevertkin             continue;
28978a978a17SVictor Perevertkin         }
28988a978a17SVictor Perevertkin 
28998a978a17SVictor Perevertkin         if (m_PurgeComplete.Method != NULL  &&
29008a978a17SVictor Perevertkin             totalIoCount == 0L           &&
29018a978a17SVictor Perevertkin             m_Dispatching == 1L) {
29028a978a17SVictor Perevertkin 
29038a978a17SVictor Perevertkin             InsertNewRequest(&NewRequest, PreviousIrql);
29048a978a17SVictor Perevertkin 
29058a978a17SVictor Perevertkin             // no more driver owned requests, we can clear the following flag:
29068a978a17SVictor Perevertkin             m_CancelDispatchedRequests = FALSE;
29078a978a17SVictor Perevertkin 
29088a978a17SVictor Perevertkin             // This can drop and re-acquire the queue lock
29098a978a17SVictor Perevertkin             ProcessPurgeComplete(&PreviousIrql);
29108a978a17SVictor Perevertkin             continue;
29118a978a17SVictor Perevertkin         }
29128a978a17SVictor Perevertkin 
29138a978a17SVictor Perevertkin         if (m_IsDevicePowerPolicyOwner       &&
29148a978a17SVictor Perevertkin             m_PowerManaged                   &&
29158a978a17SVictor Perevertkin             m_PowerReferenced                &&
29168a978a17SVictor Perevertkin             totalIoCount == 0L               &&
29178a978a17SVictor Perevertkin             m_Dispatching == 1L) {
29188a978a17SVictor Perevertkin 
29198a978a17SVictor Perevertkin             //
29208a978a17SVictor Perevertkin             // Queue has no requests, and is going idle. Notify
29218a978a17SVictor Perevertkin             // PNP/Power.
29228a978a17SVictor Perevertkin             //
29238a978a17SVictor Perevertkin             m_Device->m_PkgPnp->PowerDereference();
29248a978a17SVictor Perevertkin             m_PowerReferenced = FALSE;
29258a978a17SVictor Perevertkin             continue;
29268a978a17SVictor Perevertkin         }
29278a978a17SVictor Perevertkin 
29288a978a17SVictor Perevertkin         //
29298a978a17SVictor Perevertkin         // Look for power state transitions
29308a978a17SVictor Perevertkin         //
29318a978a17SVictor Perevertkin         if (m_PowerState != FxIoQueuePowerOn &&
29328a978a17SVictor Perevertkin             m_PowerState != FxIoQueuePowerOff) {
29338a978a17SVictor Perevertkin 
29348a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
29358a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p Power Transition State "
29368a978a17SVictor Perevertkin                                 "%!FxIoQueuePowerState!", GetObjectHandle(),
29378a978a17SVictor Perevertkin                                 m_PowerState);
29388a978a17SVictor Perevertkin 
29398a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
29408a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
29418a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
29428a978a17SVictor Perevertkin             }
29438a978a17SVictor Perevertkin 
29448a978a17SVictor Perevertkin             // Process intermediate power state
29458a978a17SVictor Perevertkin             // This can drop and re-acquire the queue lock
29468a978a17SVictor Perevertkin             if (ProcessPowerEvents(&PreviousIrql)) {
29478a978a17SVictor Perevertkin                 continue;
29488a978a17SVictor Perevertkin             }
29498a978a17SVictor Perevertkin             else {
29508a978a17SVictor Perevertkin 
29518a978a17SVictor Perevertkin                 //
29528a978a17SVictor Perevertkin                 // Return, awaiting some response from the driver
29538a978a17SVictor Perevertkin                 //
29548a978a17SVictor Perevertkin                 goto Done;
29558a978a17SVictor Perevertkin             }
29568a978a17SVictor Perevertkin         }
29578a978a17SVictor Perevertkin         else {
29588a978a17SVictor Perevertkin             // Queue is either in PowerOn or PowerOff state
29598a978a17SVictor Perevertkin             DO_NOTHING();
29608a978a17SVictor Perevertkin         }
29618a978a17SVictor Perevertkin 
29628a978a17SVictor Perevertkin         //
29638a978a17SVictor Perevertkin         // Check for queue disposing should be made after processing all
29648a978a17SVictor Perevertkin         // the events.
29658a978a17SVictor Perevertkin         //
29668a978a17SVictor Perevertkin         if (m_Disposing  &&
29678a978a17SVictor Perevertkin             totalIoCount == 0L &&
29688a978a17SVictor Perevertkin             m_Dispatching == 1L) {
29698a978a17SVictor Perevertkin 
29708a978a17SVictor Perevertkin             m_Deleted = TRUE;
29718a978a17SVictor Perevertkin 
29728a978a17SVictor Perevertkin             //
29738a978a17SVictor Perevertkin             // After this point, no other thread will be able to dispatch
29748a978a17SVictor Perevertkin             // events from this queue. Also threads that are about to call
29758a978a17SVictor Perevertkin             // this function as soon as we drop the lock below should have
29768a978a17SVictor Perevertkin             // a reference on the queue to prevent queue object from being
29778a978a17SVictor Perevertkin             // freed when we signal the dispose thread to run through.
29788a978a17SVictor Perevertkin             //
29798a978a17SVictor Perevertkin             Unlock(PreviousIrql);
29808a978a17SVictor Perevertkin 
29818a978a17SVictor Perevertkin             m_FinishDisposing.Set();
29828a978a17SVictor Perevertkin             return TRUE;
29838a978a17SVictor Perevertkin         }
29848a978a17SVictor Perevertkin 
29858a978a17SVictor Perevertkin 
29868a978a17SVictor Perevertkin         //
29878a978a17SVictor Perevertkin         // Return if power is off, can't deliver any request oriented events
29888a978a17SVictor Perevertkin         // to the driver.
29898a978a17SVictor Perevertkin         //
29908a978a17SVictor Perevertkin         if (m_PowerState == FxIoQueuePowerOff) {
29918a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
29928a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
29938a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
29948a978a17SVictor Perevertkin             }
29958a978a17SVictor Perevertkin 
29968a978a17SVictor Perevertkin             goto Done;
29978a978a17SVictor Perevertkin         }
29988a978a17SVictor Perevertkin 
29998a978a17SVictor Perevertkin         //
30008a978a17SVictor Perevertkin         // See if the queue is (still) processing requests
30018a978a17SVictor Perevertkin         //
30028a978a17SVictor Perevertkin         if (!IsState(WdfIoQueueDispatchRequests)) {
30038a978a17SVictor Perevertkin 
30048a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO,
30058a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p not in dispatching state, "
30068a978a17SVictor Perevertkin                                 "current state is %!WDF_IO_QUEUE_STATE!",
30078a978a17SVictor Perevertkin                                 GetObjectHandle(), m_QueueState);
30088a978a17SVictor Perevertkin 
30098a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
30108a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
30118a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
30128a978a17SVictor Perevertkin             }
30138a978a17SVictor Perevertkin 
30148a978a17SVictor Perevertkin             goto Done;
30158a978a17SVictor Perevertkin         }
30168a978a17SVictor Perevertkin 
30178a978a17SVictor Perevertkin         //
30188a978a17SVictor Perevertkin         // A manual dispatch queue can have a request ready notification
30198a978a17SVictor Perevertkin         //
30208a978a17SVictor Perevertkin         if (m_Type == WdfIoQueueDispatchManual) {
30218a978a17SVictor Perevertkin 
30228a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
30238a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
30248a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
30258a978a17SVictor Perevertkin             }
30268a978a17SVictor Perevertkin 
30278a978a17SVictor Perevertkin             if (m_ReadyNotify.Method != NULL && m_TransitionFromEmpty) {
30288a978a17SVictor Perevertkin 
30298a978a17SVictor Perevertkin                 // This can drop and re-acquire the lock to callback to the driver
30308a978a17SVictor Perevertkin                 ProcessReadyNotify(&PreviousIrql);
30318a978a17SVictor Perevertkin                 continue;
30328a978a17SVictor Perevertkin             }
30338a978a17SVictor Perevertkin 
30348a978a17SVictor Perevertkin             goto Done;
30358a978a17SVictor Perevertkin         }
30368a978a17SVictor Perevertkin 
30378a978a17SVictor Perevertkin         if (m_Type == WdfIoQueueDispatchSequential &&  m_DriverIoCount > 0) {
30388a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
30398a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
30408a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
30418a978a17SVictor Perevertkin             }
30428a978a17SVictor Perevertkin 
30438a978a17SVictor Perevertkin             goto Done;
30448a978a17SVictor Perevertkin         }
30458a978a17SVictor Perevertkin 
30468a978a17SVictor Perevertkin         //
30478a978a17SVictor Perevertkin         // For counted Queue's dont dispatch request to driver if the
30488a978a17SVictor Perevertkin         // m_DriverIoCount exceeds the one set by the driver writer.
30498a978a17SVictor Perevertkin         //
30508a978a17SVictor Perevertkin         if (m_Type == WdfIoQueueDispatchParallel &&
30518a978a17SVictor Perevertkin             (ULONG)m_DriverIoCount >= m_MaxParallelQueuePresentedRequests) {
30528a978a17SVictor Perevertkin             status = InsertNewRequest(&NewRequest, PreviousIrql);
30538a978a17SVictor Perevertkin             if (!NT_SUCCESS(status)) {
30548a978a17SVictor Perevertkin                 continue;   // totalIoCount may be zero now.
30558a978a17SVictor Perevertkin             }
30568a978a17SVictor Perevertkin 
30578a978a17SVictor Perevertkin             goto Done;
30588a978a17SVictor Perevertkin         }
30598a978a17SVictor Perevertkin 
30608a978a17SVictor Perevertkin         //
30618a978a17SVictor Perevertkin         // If there is a request in the queue, then retrieve that.
30628a978a17SVictor Perevertkin         //
30638a978a17SVictor Perevertkin         pRequest = NULL;
30648a978a17SVictor Perevertkin         if (m_Queue.GetRequestCount() > 0L) {
30658a978a17SVictor Perevertkin             pRequest = FxRequest::GetNextRequest(&m_Queue);
30668a978a17SVictor Perevertkin         }
30678a978a17SVictor Perevertkin 
30688a978a17SVictor Perevertkin         //
30698a978a17SVictor Perevertkin         // The request from the queue should be dispatched first
30708a978a17SVictor Perevertkin         // to preserve the ordering.
30718a978a17SVictor Perevertkin         //
30728a978a17SVictor Perevertkin         if (pRequest != NULL) {
30738a978a17SVictor Perevertkin             InsertNewRequest(&NewRequest, PreviousIrql);
30748a978a17SVictor Perevertkin         }
30758a978a17SVictor Perevertkin         else {
30768a978a17SVictor Perevertkin             //
30778a978a17SVictor Perevertkin             // If there is no request in the queue then dispatch
30788a978a17SVictor Perevertkin             // the incoming one.
30798a978a17SVictor Perevertkin             //
30808a978a17SVictor Perevertkin             pRequest = NewRequest;
30818a978a17SVictor Perevertkin             if (pRequest != NULL) {
30828a978a17SVictor Perevertkin                 pRequest->SetCurrentQueue(this);
30838a978a17SVictor Perevertkin                 SetTransitionFromEmpty();
30848a978a17SVictor Perevertkin                 NewRequest = NULL;
30858a978a17SVictor Perevertkin             }
30868a978a17SVictor Perevertkin             else {
30878a978a17SVictor Perevertkin                 goto Done;
30888a978a17SVictor Perevertkin             }
30898a978a17SVictor Perevertkin         }
30908a978a17SVictor Perevertkin 
30918a978a17SVictor Perevertkin         //
30928a978a17SVictor Perevertkin         // pRequest is not cancellable now
30938a978a17SVictor Perevertkin         //
30948a978a17SVictor Perevertkin         InsertInDriverOwnedList(pRequest);
30958a978a17SVictor Perevertkin 
30968a978a17SVictor Perevertkin         Unlock(PreviousIrql);
30978a978a17SVictor Perevertkin 
30988a978a17SVictor Perevertkin         DispatchRequestToDriver(pRequest);
30998a978a17SVictor Perevertkin 
31008a978a17SVictor Perevertkin         Lock(&PreviousIrql);
31018a978a17SVictor Perevertkin     }
31028a978a17SVictor Perevertkin 
31038a978a17SVictor Perevertkin Done:
31048a978a17SVictor Perevertkin     m_Dispatching--;
31058a978a17SVictor Perevertkin     Unlock(PreviousIrql);
31068a978a17SVictor Perevertkin     return TRUE;
31078a978a17SVictor Perevertkin }
31088a978a17SVictor Perevertkin 
31098a978a17SVictor Perevertkin VOID
DispatchRequestToDriver(__in FxRequest * pRequest)31108a978a17SVictor Perevertkin FxIoQueue::DispatchRequestToDriver(
31118a978a17SVictor Perevertkin     __in FxRequest* pRequest
31128a978a17SVictor Perevertkin     )
31138a978a17SVictor Perevertkin 
31148a978a17SVictor Perevertkin /*++
31158a978a17SVictor Perevertkin 
31168a978a17SVictor Perevertkin     Routine Description:
31178a978a17SVictor Perevertkin 
31188a978a17SVictor Perevertkin     Dispatch the next request to the driver.
31198a978a17SVictor Perevertkin 
31208a978a17SVictor Perevertkin     The IoQueue object lock is *not* held.
31218a978a17SVictor Perevertkin 
31228a978a17SVictor Perevertkin     It returns to the caller with the lock *not* held.
31238a978a17SVictor Perevertkin 
31248a978a17SVictor Perevertkin     This is called by DispatchRequests(), and should not be
31258a978a17SVictor Perevertkin     called directly in order to maintain queue processing model.
31268a978a17SVictor Perevertkin 
31278a978a17SVictor Perevertkin     Arguments:
31288a978a17SVictor Perevertkin 
31298a978a17SVictor Perevertkin     Returns:
31308a978a17SVictor Perevertkin 
31318a978a17SVictor Perevertkin --*/
31328a978a17SVictor Perevertkin 
31338a978a17SVictor Perevertkin {
31348a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals;
31358a978a17SVictor Perevertkin     NTSTATUS   Status;
31368a978a17SVictor Perevertkin     FxRequestCompletionState oldState;
31378a978a17SVictor Perevertkin     WDFREQUEST hRequest;
31388a978a17SVictor Perevertkin     FxIrp* pIrp;
31398a978a17SVictor Perevertkin 
31408a978a17SVictor Perevertkin     FxDriverGlobals = GetDriverGlobals();
31418a978a17SVictor Perevertkin 
31428a978a17SVictor Perevertkin 
31438a978a17SVictor Perevertkin 
31448a978a17SVictor Perevertkin 
31458a978a17SVictor Perevertkin 
31468a978a17SVictor Perevertkin     (VOID)pRequest->GetCurrentIrpStackLocation();
31478a978a17SVictor Perevertkin 
31488a978a17SVictor Perevertkin     pIrp = pRequest->GetFxIrp();
31498a978a17SVictor Perevertkin 
31508a978a17SVictor Perevertkin     // The Irp does not have a cancel function right now
31518a978a17SVictor Perevertkin #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
31528a978a17SVictor Perevertkin     ASSERT(pIrp->GetCurrentIrpStackLocation() != NULL);
31538a978a17SVictor Perevertkin #endif
31548a978a17SVictor Perevertkin 
31558a978a17SVictor Perevertkin     //
31568a978a17SVictor Perevertkin     // Set our completion callback on the request now before
31578a978a17SVictor Perevertkin     // calling the driver since the driver can complete the
31588a978a17SVictor Perevertkin     // request in the callback handler, and to avoid races with
31598a978a17SVictor Perevertkin     // the drivers completion thread.
31608a978a17SVictor Perevertkin     //
31618a978a17SVictor Perevertkin     // This takes a reference on the request object.
31628a978a17SVictor Perevertkin     //
31638a978a17SVictor Perevertkin     oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
31648a978a17SVictor Perevertkin     ASSERT(oldState == FxRequestCompletionStateNone);
31658a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(oldState);
31668a978a17SVictor Perevertkin 
31678a978a17SVictor Perevertkin     if (FxDriverGlobals->FxVerifierOn) {
31688a978a17SVictor Perevertkin         //
31698a978a17SVictor Perevertkin         // If the verifier is on, we do not release the extra
31708a978a17SVictor Perevertkin         // reference so we can mark the request as no longer
31718a978a17SVictor Perevertkin         // being dispatched to the driver on return from the
31728a978a17SVictor Perevertkin         // event callback to the driver
31738a978a17SVictor Perevertkin         //
31748a978a17SVictor Perevertkin 
31758a978a17SVictor Perevertkin         ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0);
31768a978a17SVictor Perevertkin 
31778a978a17SVictor Perevertkin         // Mark the request as being "owned" by the driver
31788a978a17SVictor Perevertkin         pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED |
31798a978a17SVictor Perevertkin                                    FXREQUEST_FLAG_DRIVER_DISPATCH);
31808a978a17SVictor Perevertkin     }
31818a978a17SVictor Perevertkin     else {
31828a978a17SVictor Perevertkin 
31838a978a17SVictor Perevertkin         //
31848a978a17SVictor Perevertkin         // Release our original reference. The FxRequest::Complete
31858a978a17SVictor Perevertkin         // will release the final one since we have registered a completion
31868a978a17SVictor Perevertkin         // callback handler
31878a978a17SVictor Perevertkin         //
31888a978a17SVictor Perevertkin         // We now have one reference count on the FxRequest object until
31898a978a17SVictor Perevertkin         // its completion routine runs since the completion event made
31908a978a17SVictor Perevertkin         // an extra reference, and will dereference it when it fires, or
31918a978a17SVictor Perevertkin         // its canceled.
31928a978a17SVictor Perevertkin         //
31938a978a17SVictor Perevertkin 
31948a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_STATE_TAG);
31958a978a17SVictor Perevertkin     }
31968a978a17SVictor Perevertkin 
31978a978a17SVictor Perevertkin     //
31988a978a17SVictor Perevertkin     // Attempt to dispatch it to the driver
31998a978a17SVictor Perevertkin     //
32008a978a17SVictor Perevertkin 
32018a978a17SVictor Perevertkin     //
32028a978a17SVictor Perevertkin     // Note: A driver that changes its callback pointers at runtime
32038a978a17SVictor Perevertkin     //       could run into a race here since we released the queue
32048a978a17SVictor Perevertkin     //       lock. Currently, changing parameters on a processing
32058a978a17SVictor Perevertkin     //       queue is undefined.
32068a978a17SVictor Perevertkin     //
32078a978a17SVictor Perevertkin     //       The C DDI's force the callbacks to be registered at
32088a978a17SVictor Perevertkin     //       queue creation time and avoid this race.
32098a978a17SVictor Perevertkin     //
32108a978a17SVictor Perevertkin 
32118a978a17SVictor Perevertkin     hRequest = pRequest->GetHandle();
32128a978a17SVictor Perevertkin 
32138a978a17SVictor Perevertkin     UCHAR majorFunction = pIrp->GetMajorFunction();
32148a978a17SVictor Perevertkin 
32158a978a17SVictor Perevertkin     if ((majorFunction == IRP_MJ_READ) && m_IoRead.Method) {
32168a978a17SVictor Perevertkin         ULONG readLength = pIrp->GetParameterReadLength();
32178a978a17SVictor Perevertkin 
32188a978a17SVictor Perevertkin         //
32198a978a17SVictor Perevertkin         // Complete zero length reads with STATUS_SUCCESS unless the
32208a978a17SVictor Perevertkin         // driver specified it wants them delivered.
32218a978a17SVictor Perevertkin         //
32228a978a17SVictor Perevertkin         if ((readLength == 0) &&
32238a978a17SVictor Perevertkin             !m_AllowZeroLengthRequests) {
32248a978a17SVictor Perevertkin 
32258a978a17SVictor Perevertkin             DoTraceLevelMessage(
32268a978a17SVictor Perevertkin                 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
32278a978a17SVictor Perevertkin                 "Zero length WDFREQUEST 0x%p completed automatically "
32288a978a17SVictor Perevertkin                 "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
32298a978a17SVictor Perevertkin 
32308a978a17SVictor Perevertkin             pRequest->Complete(STATUS_SUCCESS);
32318a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
32328a978a17SVictor Perevertkin                 //
32338a978a17SVictor Perevertkin                 // Release the reference taken in the call to SetCompletionState
32348a978a17SVictor Perevertkin                 // at the top of the function.
32358a978a17SVictor Perevertkin                 //
32368a978a17SVictor Perevertkin                 pRequest->RELEASE(FXREQUEST_STATE_TAG);
32378a978a17SVictor Perevertkin             }
32388a978a17SVictor Perevertkin             return;
32398a978a17SVictor Perevertkin         }
32408a978a17SVictor Perevertkin 
32418a978a17SVictor Perevertkin         pRequest->SetPresented();
32428a978a17SVictor Perevertkin 
32438a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
32448a978a17SVictor Perevertkin                             "Calling driver EvtIoRead for WDFREQUEST 0x%p",
32458a978a17SVictor Perevertkin                             hRequest);
32468a978a17SVictor Perevertkin 
32478a978a17SVictor Perevertkin         m_IoRead.Invoke(
32488a978a17SVictor Perevertkin             GetHandle(),
32498a978a17SVictor Perevertkin             hRequest,
32508a978a17SVictor Perevertkin             readLength
32518a978a17SVictor Perevertkin             );
32528a978a17SVictor Perevertkin     }
32538a978a17SVictor Perevertkin     else if ((majorFunction == IRP_MJ_WRITE) && m_IoWrite.Method) {
32548a978a17SVictor Perevertkin         ULONG writeLength = pIrp->GetParameterWriteLength();
32558a978a17SVictor Perevertkin 
32568a978a17SVictor Perevertkin         //
32578a978a17SVictor Perevertkin         // Complete zero length writes with STATUS_SUCCESS unless the
32588a978a17SVictor Perevertkin         // driver specified it wants them delivered.
32598a978a17SVictor Perevertkin         //
32608a978a17SVictor Perevertkin         if ((writeLength == 0) &&
32618a978a17SVictor Perevertkin             !m_AllowZeroLengthRequests) {
32628a978a17SVictor Perevertkin 
32638a978a17SVictor Perevertkin             DoTraceLevelMessage(
32648a978a17SVictor Perevertkin                 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
32658a978a17SVictor Perevertkin                 "Zero length WDFREQUEST 0x%p completed automatically "
32668a978a17SVictor Perevertkin                 "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
32678a978a17SVictor Perevertkin 
32688a978a17SVictor Perevertkin             pRequest->Complete(STATUS_SUCCESS);
32698a978a17SVictor Perevertkin 
32708a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
32718a978a17SVictor Perevertkin                 //
32728a978a17SVictor Perevertkin                 // Release the reference taken in the call to SetCompletionState
32738a978a17SVictor Perevertkin                 // at the top of the function.
32748a978a17SVictor Perevertkin                 //
32758a978a17SVictor Perevertkin                 pRequest->RELEASE(FXREQUEST_STATE_TAG);
32768a978a17SVictor Perevertkin             }
32778a978a17SVictor Perevertkin             return;
32788a978a17SVictor Perevertkin         }
32798a978a17SVictor Perevertkin 
32808a978a17SVictor Perevertkin         pRequest->SetPresented();
32818a978a17SVictor Perevertkin 
32828a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
32838a978a17SVictor Perevertkin                             "Calling driver EvtIoWrite for WDFREQUEST 0x%p",
32848a978a17SVictor Perevertkin                             pRequest->GetObjectHandle());
32858a978a17SVictor Perevertkin 
32868a978a17SVictor Perevertkin         m_IoWrite.Invoke(
32878a978a17SVictor Perevertkin             GetHandle(),
32888a978a17SVictor Perevertkin             hRequest,
32898a978a17SVictor Perevertkin             writeLength
32908a978a17SVictor Perevertkin             );
32918a978a17SVictor Perevertkin     }
32928a978a17SVictor Perevertkin     else if ((majorFunction == IRP_MJ_DEVICE_CONTROL) && m_IoDeviceControl.Method) {
32938a978a17SVictor Perevertkin 
32948a978a17SVictor Perevertkin         pRequest->SetPresented();
32958a978a17SVictor Perevertkin 
32968a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
32978a978a17SVictor Perevertkin                             "Calling driver EvtIoDeviceControl for "
32988a978a17SVictor Perevertkin                             "WDFREQUEST 0x%p", hRequest);
32998a978a17SVictor Perevertkin 
33008a978a17SVictor Perevertkin         m_IoDeviceControl.Invoke(
33018a978a17SVictor Perevertkin             GetHandle(),
33028a978a17SVictor Perevertkin             hRequest,
33038a978a17SVictor Perevertkin             pIrp->GetParameterIoctlOutputBufferLength(),
33048a978a17SVictor Perevertkin             pIrp->GetParameterIoctlInputBufferLength(),
33058a978a17SVictor Perevertkin             pIrp->GetParameterIoctlCode()
33068a978a17SVictor Perevertkin             );
33078a978a17SVictor Perevertkin     }
33088a978a17SVictor Perevertkin 
33098a978a17SVictor Perevertkin     else if ( (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) && m_IoInternalDeviceControl.Method) {
33108a978a17SVictor Perevertkin 
33118a978a17SVictor Perevertkin         pRequest->SetPresented();
33128a978a17SVictor Perevertkin 
33138a978a17SVictor Perevertkin         DoTraceLevelMessage(
33148a978a17SVictor Perevertkin             FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
33158a978a17SVictor Perevertkin             "Calling driver EvtIoInternalDeviceControl for WDFREQUEST 0x%p",
33168a978a17SVictor Perevertkin             hRequest);
33178a978a17SVictor Perevertkin 
33188a978a17SVictor Perevertkin         m_IoInternalDeviceControl.Invoke(
33198a978a17SVictor Perevertkin             GetHandle(),
33208a978a17SVictor Perevertkin             hRequest,
33218a978a17SVictor Perevertkin             pIrp->GetParameterIoctlOutputBufferLength(),
33228a978a17SVictor Perevertkin             pIrp->GetParameterIoctlInputBufferLength(),
33238a978a17SVictor Perevertkin             pIrp->GetParameterIoctlCode()
33248a978a17SVictor Perevertkin             );
33258a978a17SVictor Perevertkin     }
33268a978a17SVictor Perevertkin     else {
33278a978a17SVictor Perevertkin 
33288a978a17SVictor Perevertkin         //
33298a978a17SVictor Perevertkin         // If we have an IoStart registered, call it
33308a978a17SVictor Perevertkin         //
33318a978a17SVictor Perevertkin         if (m_IoDefault.Method) {
33328a978a17SVictor Perevertkin 
33338a978a17SVictor Perevertkin             DoTraceLevelMessage(
33348a978a17SVictor Perevertkin                 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
33358a978a17SVictor Perevertkin                 "Calling driver EvtIoDefault for WDFREQUEST 0x%p", hRequest);
33368a978a17SVictor Perevertkin 
33378a978a17SVictor Perevertkin 
33388a978a17SVictor Perevertkin             //
33398a978a17SVictor Perevertkin             // If we don't allow zero length requests, we must dig in whether
33408a978a17SVictor Perevertkin             // its a read or a write
33418a978a17SVictor Perevertkin             //
33428a978a17SVictor Perevertkin             if (!m_AllowZeroLengthRequests) {
33438a978a17SVictor Perevertkin 
33448a978a17SVictor Perevertkin                 if (majorFunction == IRP_MJ_READ) {
33458a978a17SVictor Perevertkin 
33468a978a17SVictor Perevertkin                     if (pIrp->GetParameterReadLength() == 0) {
33478a978a17SVictor Perevertkin 
33488a978a17SVictor Perevertkin                         DoTraceLevelMessage(
33498a978a17SVictor Perevertkin                             FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
33508a978a17SVictor Perevertkin                             "Zero length WDFREQUEST 0x%p completed automatically "
33518a978a17SVictor Perevertkin                             "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
33528a978a17SVictor Perevertkin 
33538a978a17SVictor Perevertkin                         pRequest->Complete(STATUS_SUCCESS);
33548a978a17SVictor Perevertkin                         if (FxDriverGlobals->FxVerifierOn) {
33558a978a17SVictor Perevertkin                             //
33568a978a17SVictor Perevertkin                             // Release the reference taken in the call to SetCompletionState
33578a978a17SVictor Perevertkin                             // at the top of the function.
33588a978a17SVictor Perevertkin                             //
33598a978a17SVictor Perevertkin                             pRequest->RELEASE(FXREQUEST_STATE_TAG);
33608a978a17SVictor Perevertkin                         }
33618a978a17SVictor Perevertkin                         return;
33628a978a17SVictor Perevertkin                     }
33638a978a17SVictor Perevertkin                 }
33648a978a17SVictor Perevertkin                 else if (majorFunction == IRP_MJ_WRITE) {
33658a978a17SVictor Perevertkin 
33668a978a17SVictor Perevertkin                         if (pIrp->GetParameterWriteLength() == 0) {
33678a978a17SVictor Perevertkin 
33688a978a17SVictor Perevertkin                             pRequest->Complete(STATUS_SUCCESS);
33698a978a17SVictor Perevertkin 
33708a978a17SVictor Perevertkin                             DoTraceLevelMessage(
33718a978a17SVictor Perevertkin                                 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
33728a978a17SVictor Perevertkin                                 "Zero length WDFREQUEST 0x%p completed automatically "
33738a978a17SVictor Perevertkin                                 "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
33748a978a17SVictor Perevertkin 
33758a978a17SVictor Perevertkin                             if (FxDriverGlobals->FxVerifierOn) {
33768a978a17SVictor Perevertkin                                 //
33778a978a17SVictor Perevertkin                                 // Release the reference taken in the call to SetCompletionState
33788a978a17SVictor Perevertkin                                 // at the top of the function.
33798a978a17SVictor Perevertkin                                 //
33808a978a17SVictor Perevertkin                                 pRequest->RELEASE(FXREQUEST_STATE_TAG);
33818a978a17SVictor Perevertkin                             }
33828a978a17SVictor Perevertkin                             return;
33838a978a17SVictor Perevertkin                         }
33848a978a17SVictor Perevertkin                     }
33858a978a17SVictor Perevertkin             }
33868a978a17SVictor Perevertkin 
33878a978a17SVictor Perevertkin             pRequest->SetPresented();
33888a978a17SVictor Perevertkin 
33898a978a17SVictor Perevertkin             m_IoDefault.Invoke(GetHandle(), hRequest);
33908a978a17SVictor Perevertkin         }
33918a978a17SVictor Perevertkin         else {
33928a978a17SVictor Perevertkin             Status = STATUS_INVALID_DEVICE_REQUEST;
33938a978a17SVictor Perevertkin 
33948a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
33958a978a17SVictor Perevertkin                                 "Driver has no event callback "
33968a978a17SVictor Perevertkin                                 "for %!WDF_REQUEST_TYPE!, completing WDFREQUEST 0x%p with "
33978a978a17SVictor Perevertkin                                 "%!STATUS!",
33988a978a17SVictor Perevertkin                                 majorFunction,
33998a978a17SVictor Perevertkin                                 pRequest,
34008a978a17SVictor Perevertkin                                 Status);
34018a978a17SVictor Perevertkin 
34028a978a17SVictor Perevertkin             pRequest->Complete(Status);
34038a978a17SVictor Perevertkin 
34048a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
34058a978a17SVictor Perevertkin                 //
34068a978a17SVictor Perevertkin                 // Release our extra verifier reference now
34078a978a17SVictor Perevertkin                 //
34088a978a17SVictor Perevertkin                 // Release the reference taken in the call to SetCompletionState
34098a978a17SVictor Perevertkin                 // at the top of the function.
34108a978a17SVictor Perevertkin                 //
34118a978a17SVictor Perevertkin                 pRequest->RELEASE(FXREQUEST_STATE_TAG);
34128a978a17SVictor Perevertkin             }
34138a978a17SVictor Perevertkin 
34148a978a17SVictor Perevertkin             return;
34158a978a17SVictor Perevertkin         }
34168a978a17SVictor Perevertkin     }
34178a978a17SVictor Perevertkin 
34188a978a17SVictor Perevertkin     // ******************************
34198a978a17SVictor Perevertkin     // Request may now be a freed object unless verifier is on. Only touch
34208a978a17SVictor Perevertkin     // request if verifier is on.
34218a978a17SVictor Perevertkin     // ******************************
34228a978a17SVictor Perevertkin 
34238a978a17SVictor Perevertkin     if (FxDriverGlobals->FxVerifierOn) {
34248a978a17SVictor Perevertkin 
34258a978a17SVictor Perevertkin         //
34268a978a17SVictor Perevertkin         // If the request has been forwarded, don't clear this
34278a978a17SVictor Perevertkin         // since the new queue may already be dispatching in a new thread or DPC
34288a978a17SVictor Perevertkin         //
34298a978a17SVictor Perevertkin         if ((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_FORWARDED) == 0x0) {
34308a978a17SVictor Perevertkin             pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_DISPATCH);
34318a978a17SVictor Perevertkin         }
34328a978a17SVictor Perevertkin 
34338a978a17SVictor Perevertkin         //
34348a978a17SVictor Perevertkin         // Release our extra verifier reference now
34358a978a17SVictor Perevertkin         //
34368a978a17SVictor Perevertkin         // Release the reference taken in the call to SetCompletionState
34378a978a17SVictor Perevertkin 
34388a978a17SVictor Perevertkin         // at the top of the function.
34398a978a17SVictor Perevertkin         //
34408a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_STATE_TAG);
34418a978a17SVictor Perevertkin     }
34428a978a17SVictor Perevertkin 
34438a978a17SVictor Perevertkin     // Driver accepted a request
34448a978a17SVictor Perevertkin     return;
34458a978a17SVictor Perevertkin }
34468a978a17SVictor Perevertkin 
34478a978a17SVictor Perevertkin 
34488a978a17SVictor Perevertkin //
34498a978a17SVictor Perevertkin // Register a callback when the Queue has a request.
34508a978a17SVictor Perevertkin //
34518a978a17SVictor Perevertkin // Only valid for a manual Queue.
34528a978a17SVictor Perevertkin //
34538a978a17SVictor Perevertkin _Must_inspect_result_
34548a978a17SVictor Perevertkin NTSTATUS
ReadyNotify(__in PFN_WDF_IO_QUEUE_STATE QueueReady,__in_opt WDFCONTEXT Context)34558a978a17SVictor Perevertkin FxIoQueue::ReadyNotify(
34568a978a17SVictor Perevertkin     __in PFN_WDF_IO_QUEUE_STATE QueueReady,
34578a978a17SVictor Perevertkin     __in_opt WDFCONTEXT              Context
34588a978a17SVictor Perevertkin     )
34598a978a17SVictor Perevertkin {
34608a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
34618a978a17SVictor Perevertkin     KIRQL irql;
34628a978a17SVictor Perevertkin     NTSTATUS status;
34638a978a17SVictor Perevertkin 
34648a978a17SVictor Perevertkin     // Only valid for a manually dispatched Queue
34658a978a17SVictor Perevertkin     if (m_Type != WdfIoQueueDispatchManual) {
34668a978a17SVictor Perevertkin         status = STATUS_INVALID_DEVICE_REQUEST;
34678a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
34688a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is "
34698a978a17SVictor Perevertkin                             "not a Manual queue, ReadyNotify is only valid "
34708a978a17SVictor Perevertkin                             "on a manual Queue, %!STATUS!",
34718a978a17SVictor Perevertkin                             GetObjectHandle(), status);
34728a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(FxDriverGlobals);
34738a978a17SVictor Perevertkin         return status;
34748a978a17SVictor Perevertkin     }
34758a978a17SVictor Perevertkin 
34768a978a17SVictor Perevertkin     Lock(&irql);
34778a978a17SVictor Perevertkin 
34788a978a17SVictor Perevertkin     // If the queue is deleted, requests will not be serviced anymore
34798a978a17SVictor Perevertkin     if (m_Deleted) {
34808a978a17SVictor Perevertkin         Unlock(irql);
34818a978a17SVictor Perevertkin         return STATUS_DELETE_PENDING;
34828a978a17SVictor Perevertkin     }
34838a978a17SVictor Perevertkin 
34848a978a17SVictor Perevertkin     if (QueueReady != NULL) {
34858a978a17SVictor Perevertkin 
34868a978a17SVictor Perevertkin         //
34878a978a17SVictor Perevertkin         // Only one ReadyNotify registration per Queue is allowed
34888a978a17SVictor Perevertkin         //
34898a978a17SVictor Perevertkin         if (m_ReadyNotify.Method != NULL) {
34908a978a17SVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
34918a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
34928a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p "
34938a978a17SVictor Perevertkin                                 "already has a ReadyNotify callback 0x%p"
34948a978a17SVictor Perevertkin                                 "registered, %!STATUS!",GetObjectHandle(),
34958a978a17SVictor Perevertkin                                 &m_ReadyNotify, status);
34968a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(FxDriverGlobals);
34978a978a17SVictor Perevertkin             Unlock(irql);
34988a978a17SVictor Perevertkin             return status;
34998a978a17SVictor Perevertkin         }
35008a978a17SVictor Perevertkin 
35018a978a17SVictor Perevertkin         m_ReadyNotify.Method = QueueReady;
35028a978a17SVictor Perevertkin         m_ReadyNotifyContext = Context;
35038a978a17SVictor Perevertkin     }
35048a978a17SVictor Perevertkin     else {
35058a978a17SVictor Perevertkin 
35068a978a17SVictor Perevertkin         //
35078a978a17SVictor Perevertkin         // A request to cancel ready notifications
35088a978a17SVictor Perevertkin         //
35098a978a17SVictor Perevertkin 
35108a978a17SVictor Perevertkin         // If already cancelled, the driver is confused, notify it
35118a978a17SVictor Perevertkin         if (m_ReadyNotify.Method == NULL) {
35128a978a17SVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
35138a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
35148a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p "
35158a978a17SVictor Perevertkin                                 "does not have a ReadyNotify to cancel, %!STATUS!",
35168a978a17SVictor Perevertkin                                 GetObjectHandle(), status);
35178a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(FxDriverGlobals);
35188a978a17SVictor Perevertkin             Unlock(irql);
35198a978a17SVictor Perevertkin             return status;
35208a978a17SVictor Perevertkin         }
35218a978a17SVictor Perevertkin 
35228a978a17SVictor Perevertkin         //
35238a978a17SVictor Perevertkin         // The queue should be stopped from dispatching requests to
35248a978a17SVictor Perevertkin         // avoid missing state transistions between clear and set.
35258a978a17SVictor Perevertkin         //
35268a978a17SVictor Perevertkin         if(IsState(WdfIoQueueDispatchRequests)) {
35278a978a17SVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
35288a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
35298a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p "
35308a978a17SVictor Perevertkin                                 "should be stopped before clearing ReadyNotify callback "
35318a978a17SVictor Perevertkin                                 "0x%p registered, %!STATUS!",GetObjectHandle(),
35328a978a17SVictor Perevertkin                                 &m_ReadyNotify, status);
35338a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(FxDriverGlobals);
35348a978a17SVictor Perevertkin             Unlock(irql);
35358a978a17SVictor Perevertkin             return status;
35368a978a17SVictor Perevertkin 
35378a978a17SVictor Perevertkin         }
35388a978a17SVictor Perevertkin 
35398a978a17SVictor Perevertkin         m_ReadyNotify.Method = NULL;
35408a978a17SVictor Perevertkin         m_ReadyNotifyContext = NULL;
35418a978a17SVictor Perevertkin     }
35428a978a17SVictor Perevertkin 
35438a978a17SVictor Perevertkin     //
35448a978a17SVictor Perevertkin     // Check for ready notification since there may already be an event
35458a978a17SVictor Perevertkin     //
35468a978a17SVictor Perevertkin     DispatchEvents(irql);
35478a978a17SVictor Perevertkin 
35488a978a17SVictor Perevertkin     return STATUS_SUCCESS;
35498a978a17SVictor Perevertkin }
35508a978a17SVictor Perevertkin 
35518a978a17SVictor Perevertkin VOID
QueueStart()35528a978a17SVictor Perevertkin FxIoQueue::QueueStart(
35538a978a17SVictor Perevertkin     )
35548a978a17SVictor Perevertkin {
35558a978a17SVictor Perevertkin     KIRQL irql;
35568a978a17SVictor Perevertkin 
35578a978a17SVictor Perevertkin     Lock(&irql);
35588a978a17SVictor Perevertkin 
35598a978a17SVictor Perevertkin     SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests | FxIoQueueSetDispatchRequests) );
35608a978a17SVictor Perevertkin 
35618a978a17SVictor Perevertkin     //
35628a978a17SVictor Perevertkin     // We should set the flag to notify the driver on queue start in case
35638a978a17SVictor Perevertkin     // the driver stops the queue while the ReadyNotify callback is executing.
35648a978a17SVictor Perevertkin     // If that happens, the request will be left in the manual queue with
35658a978a17SVictor Perevertkin     // m_TransitionFromEmpty cleared.
35668a978a17SVictor Perevertkin     //
35678a978a17SVictor Perevertkin     if (m_Queue.GetRequestCount() > 0L) {
35688a978a17SVictor Perevertkin         m_TransitionFromEmpty = TRUE;
35698a978a17SVictor Perevertkin         m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE;
35708a978a17SVictor Perevertkin     }
35718a978a17SVictor Perevertkin 
35728a978a17SVictor Perevertkin     //
35738a978a17SVictor Perevertkin     // We may have transitioned to a status that resumes
35748a978a17SVictor Perevertkin     // processing, so call dispatch function.
35758a978a17SVictor Perevertkin     //
35768a978a17SVictor Perevertkin 
35778a978a17SVictor Perevertkin     DispatchEvents(irql);
35788a978a17SVictor Perevertkin 
35798a978a17SVictor Perevertkin     return;
35808a978a17SVictor Perevertkin }
35818a978a17SVictor Perevertkin 
35828a978a17SVictor Perevertkin _Must_inspect_result_
35838a978a17SVictor Perevertkin NTSTATUS
QueueIdle(__in BOOLEAN CancelRequests,__in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,__in_opt WDFCONTEXT Context)35848a978a17SVictor Perevertkin FxIoQueue::QueueIdle(
35858a978a17SVictor Perevertkin     __in BOOLEAN                    CancelRequests,
35868a978a17SVictor Perevertkin     __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,
35878a978a17SVictor Perevertkin     __in_opt WDFCONTEXT             Context
35888a978a17SVictor Perevertkin     )
35898a978a17SVictor Perevertkin 
35908a978a17SVictor Perevertkin /*++
35918a978a17SVictor Perevertkin 
35928a978a17SVictor Perevertkin Routine Description:
35938a978a17SVictor Perevertkin 
35948a978a17SVictor Perevertkin     Idle (stop) the Queue.
35958a978a17SVictor Perevertkin 
35968a978a17SVictor Perevertkin     If CancelRequests == TRUE,
35978a978a17SVictor Perevertkin         1) any requests in the Queue that have not been presented to the device driver are
35988a978a17SVictor Perevertkin             completed with STATUS_CANCELLED.
35998a978a17SVictor Perevertkin         2) any requests that the driver is operating on that are cancelable will have an
36008a978a17SVictor Perevertkin             I/O Cancel done on them.
36018a978a17SVictor Perevertkin         3) any forward progress queued IRPs are completed with STATUS_CANCELLED.
36028a978a17SVictor Perevertkin 
36038a978a17SVictor Perevertkin Arguments:
36048a978a17SVictor Perevertkin 
36058a978a17SVictor Perevertkin Returns:
36068a978a17SVictor Perevertkin 
36078a978a17SVictor Perevertkin --*/
36088a978a17SVictor Perevertkin 
36098a978a17SVictor Perevertkin {
36108a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS  fxDriverGlobals = GetDriverGlobals();
36118a978a17SVictor Perevertkin     KIRQL               irql;
36128a978a17SVictor Perevertkin     NTSTATUS            status;
36138a978a17SVictor Perevertkin     LIST_ENTRY          fwrIrpList = {0};
36148a978a17SVictor Perevertkin     FxRequest*          request;
36158a978a17SVictor Perevertkin 
36168a978a17SVictor Perevertkin 
36178a978a17SVictor Perevertkin     Lock(&irql);
36188a978a17SVictor Perevertkin 
36198a978a17SVictor Perevertkin     // If the queue is deleted, requests will not be serviced anymore
36208a978a17SVictor Perevertkin     if (m_Deleted) {
36218a978a17SVictor Perevertkin         status = STATUS_DELETE_PENDING;
36228a978a17SVictor Perevertkin         DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
36238a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is already deleted, %!STATUS!",
36248a978a17SVictor Perevertkin                             GetObjectHandle(), status);
36258a978a17SVictor Perevertkin         Unlock(irql);
36268a978a17SVictor Perevertkin 
36278a978a17SVictor Perevertkin         return status;
36288a978a17SVictor Perevertkin     }
36298a978a17SVictor Perevertkin 
36308a978a17SVictor Perevertkin     //
36318a978a17SVictor Perevertkin     // If a IdleComplete callback is supplied, we must register it up
36328a978a17SVictor Perevertkin     // front since a transition empty could occur in another thread.
36338a978a17SVictor Perevertkin     //
36348a978a17SVictor Perevertkin     if (IdleComplete != NULL) {
36358a978a17SVictor Perevertkin 
36368a978a17SVictor Perevertkin         //
36378a978a17SVictor Perevertkin         // Only one Idle or Purge Complete callback can be outstanding
36388a978a17SVictor Perevertkin         // at a time per Queue
36398a978a17SVictor Perevertkin         //
36408a978a17SVictor Perevertkin         if (m_IdleComplete.Method != NULL) {
36418a978a17SVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
36428a978a17SVictor Perevertkin             DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
36438a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p already has a "
36448a978a17SVictor Perevertkin                                 "IdleComplete callback registered 0x%p, "
36458a978a17SVictor Perevertkin                                 "%!STATUS!", GetObjectHandle(),
36468a978a17SVictor Perevertkin                                 m_IdleComplete.Method,
36478a978a17SVictor Perevertkin                                 status);
36488a978a17SVictor Perevertkin             Unlock(irql);
36498a978a17SVictor Perevertkin 
36508a978a17SVictor Perevertkin             return status;
36518a978a17SVictor Perevertkin         }
36528a978a17SVictor Perevertkin 
36538a978a17SVictor Perevertkin         m_IdleComplete.Method = IdleComplete;
36548a978a17SVictor Perevertkin         m_IdleCompleteContext = Context;
36558a978a17SVictor Perevertkin     }
36568a978a17SVictor Perevertkin 
36578a978a17SVictor Perevertkin     // Set Accept request and Clear dispatch requests
36588a978a17SVictor Perevertkin     SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests | FxIoQueueClearDispatchRequests));
36598a978a17SVictor Perevertkin 
36608a978a17SVictor Perevertkin     //
36618a978a17SVictor Perevertkin     // Get ready to cancel current queued requests. Note that we don't want to
36628a978a17SVictor Perevertkin     // prevent new requests from being queue, i.e., it is legal for an upper
36638a978a17SVictor Perevertkin     // driver can resend another request in its completion routine.
36648a978a17SVictor Perevertkin     //
36658a978a17SVictor Perevertkin     if (CancelRequests) {
36668a978a17SVictor Perevertkin         //
36678a978a17SVictor Perevertkin         // Driver wants to abort/complete all queued request and cancel or
36688a978a17SVictor Perevertkin         // wait for all requests the driver is currently handling. Thus we must
36698a978a17SVictor Perevertkin         // prevent the driver from requeuing stale requests.
36708a978a17SVictor Perevertkin         // The 'cancel driver requests'  field gives us this ability.
36718a978a17SVictor Perevertkin         // It is set here, and cleared when:
36728a978a17SVictor Perevertkin         //  (a) Driver doesn't own any more requests, or
36738a978a17SVictor Perevertkin         //  (b) the driver calls WdfIoQueueStart again (dispatch gate is opened).
36748a978a17SVictor Perevertkin         // When set, the framework automatically deletes  any request that the
36758a978a17SVictor Perevertkin         // driver requeues.
36768a978a17SVictor Perevertkin         //
36778a978a17SVictor Perevertkin         m_CancelDispatchedRequests = TRUE;
36788a978a17SVictor Perevertkin 
36798a978a17SVictor Perevertkin         request = NULL; // Initial tag used by PeekRequest.
36808a978a17SVictor Perevertkin                                       #pragma warning(disable:4127)
36818a978a17SVictor Perevertkin         while (TRUE) {
36828a978a17SVictor Perevertkin                                       #pragma warning(default:4127)
36838a978a17SVictor Perevertkin             status = FxRequest::PeekRequest(&m_Queue,       // in:queue
36848a978a17SVictor Perevertkin                                             request,        // in:tag.
36858a978a17SVictor Perevertkin                                             NULL,           // in:file_obj
36868a978a17SVictor Perevertkin                                             NULL,           // out:parameters
36878a978a17SVictor Perevertkin                                             &request);      // out:request.
36888a978a17SVictor Perevertkin             if (status != STATUS_SUCCESS) {
36898a978a17SVictor Perevertkin                 ASSERT(status != STATUS_NOT_FOUND);
36908a978a17SVictor Perevertkin                 break;
36918a978a17SVictor Perevertkin             }
36928a978a17SVictor Perevertkin 
36938a978a17SVictor Perevertkin             //
36948a978a17SVictor Perevertkin             // Tag this request and release the extra ref that Peek() takes.
36958a978a17SVictor Perevertkin             //
36968a978a17SVictor Perevertkin             request->m_Canceled = TRUE;
36978a978a17SVictor Perevertkin 
36988a978a17SVictor Perevertkin #pragma prefast(suppress:__WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "This is the tag value used in the ADDREF of Peek()")
36998a978a17SVictor Perevertkin             request->RELEASE(NULL);
37008a978a17SVictor Perevertkin         }
37018a978a17SVictor Perevertkin 
37028a978a17SVictor Perevertkin         //
37038a978a17SVictor Perevertkin         // Move forward progress IRPs to a temp list; we use this logic to
37048a978a17SVictor Perevertkin         // allow new  IRPs to be pended to the original list.
37058a978a17SVictor Perevertkin         //
37068a978a17SVictor Perevertkin         if (IsForwardProgressQueue()) {
37078a978a17SVictor Perevertkin             InitializeListHead(&fwrIrpList);
37088a978a17SVictor Perevertkin             GetForwardProgressIrps(&fwrIrpList, NULL);
37098a978a17SVictor Perevertkin         }
37108a978a17SVictor Perevertkin     }
37118a978a17SVictor Perevertkin 
37128a978a17SVictor Perevertkin     // Unlock queue lock
37138a978a17SVictor Perevertkin     Unlock(irql);
37148a978a17SVictor Perevertkin 
37158a978a17SVictor Perevertkin     if (CancelRequests) {
37168a978a17SVictor Perevertkin                               #pragma warning(disable:4127)
37178a978a17SVictor Perevertkin         while (TRUE) {
37188a978a17SVictor Perevertkin                               #pragma warning(default:4127)
37198a978a17SVictor Perevertkin             //
37208a978a17SVictor Perevertkin             // Get the next FxRequest from the cancel safe queue
37218a978a17SVictor Perevertkin             //
37228a978a17SVictor Perevertkin             Lock(&irql);
37238a978a17SVictor Perevertkin             request = FxRequest::GetNextRequest(&m_Queue);
37248a978a17SVictor Perevertkin             if (request == NULL) {
37258a978a17SVictor Perevertkin                 DoTraceLevelMessage(
37268a978a17SVictor Perevertkin                             fxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
37278a978a17SVictor Perevertkin                             "All WDFQUEUE 0x%p requests cancelled",
37288a978a17SVictor Perevertkin                             GetObjectHandle());
37298a978a17SVictor Perevertkin                 Unlock(irql);
37308a978a17SVictor Perevertkin                 break;
37318a978a17SVictor Perevertkin             }
37328a978a17SVictor Perevertkin 
37338a978a17SVictor Perevertkin             // Irp is not cancellable now
37348a978a17SVictor Perevertkin 
37358a978a17SVictor Perevertkin             //
37368a978a17SVictor Perevertkin             // Make sure to purged requests only if:
37378a978a17SVictor Perevertkin             // (a) the request was present when we started this operation.
37388a978a17SVictor Perevertkin             // (b) any following request that is marked as cancelled.
37398a978a17SVictor Perevertkin             //
37408a978a17SVictor Perevertkin             if (request->IsCancelled() == FALSE) {
37418a978a17SVictor Perevertkin                 status = request->InsertHeadIrpQueue(&m_Queue, NULL);
37428a978a17SVictor Perevertkin                 if (NT_SUCCESS(status)) {
37438a978a17SVictor Perevertkin                     Unlock(irql);
37448a978a17SVictor Perevertkin                     break;
37458a978a17SVictor Perevertkin                 }
37468a978a17SVictor Perevertkin 
37478a978a17SVictor Perevertkin                 ASSERT(status == STATUS_CANCELLED);
37488a978a17SVictor Perevertkin             }
37498a978a17SVictor Perevertkin             DoTraceLevelMessage(
37508a978a17SVictor Perevertkin                         fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO,
37518a978a17SVictor Perevertkin                         "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p",
37528a978a17SVictor Perevertkin                         request->GetHandle(),GetObjectHandle());
37538a978a17SVictor Perevertkin 
37548a978a17SVictor Perevertkin             //
37558a978a17SVictor Perevertkin             // We must add a reference since the CancelForQueue path
37568a978a17SVictor Perevertkin             // assumes we were on the FxIrpQueue with the extra reference
37578a978a17SVictor Perevertkin             //
37588a978a17SVictor Perevertkin             request->ADDREF(FXREQUEST_QUEUE_TAG);
37598a978a17SVictor Perevertkin 
37608a978a17SVictor Perevertkin             //
37618a978a17SVictor Perevertkin             // Mark the request as cancelled, place it on the cancel list,
37628a978a17SVictor Perevertkin             // and schedule the cancel event to the driver
37638a978a17SVictor Perevertkin             //
37648a978a17SVictor Perevertkin             CancelForQueue(request, irql);
37658a978a17SVictor Perevertkin         }
37668a978a17SVictor Perevertkin 
37678a978a17SVictor Perevertkin         //
37688a978a17SVictor Perevertkin         // Walk the driver cancelable list cancelling the requests.
37698a978a17SVictor Perevertkin         //
37708a978a17SVictor Perevertkin                                                   #pragma warning(disable:4127)
37718a978a17SVictor Perevertkin         while (TRUE) {
37728a978a17SVictor Perevertkin                                                   #pragma warning(default:4127)
37738a978a17SVictor Perevertkin             //
37748a978a17SVictor Perevertkin             // Get the next request of driver cancelable requests
37758a978a17SVictor Perevertkin             //
37768a978a17SVictor Perevertkin             Lock(&irql);
37778a978a17SVictor Perevertkin             request = FxRequest::GetNextRequest(&m_DriverCancelable);
37788a978a17SVictor Perevertkin             if (request == NULL) {
37798a978a17SVictor Perevertkin                 DoTraceLevelMessage(
37808a978a17SVictor Perevertkin                             fxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
37818a978a17SVictor Perevertkin                             "All driver cancellable requests cancelled "
37828a978a17SVictor Perevertkin                             " in WDFQUEUE 0x%p",
37838a978a17SVictor Perevertkin                             GetObjectHandle());
37848a978a17SVictor Perevertkin                 Unlock(irql);
37858a978a17SVictor Perevertkin                 break;
37868a978a17SVictor Perevertkin             }
37878a978a17SVictor Perevertkin 
37888a978a17SVictor Perevertkin             request->m_Canceled = TRUE;
37898a978a17SVictor Perevertkin 
37908a978a17SVictor Perevertkin             Unlock(irql);
37918a978a17SVictor Perevertkin 
37928a978a17SVictor Perevertkin             //
37938a978a17SVictor Perevertkin             // If the driver follows the pattern of removing cancel status
37948a978a17SVictor Perevertkin             // from the request before completion, then there is no race
37958a978a17SVictor Perevertkin             // with this routine since we will not be able to retrieve any
37968a978a17SVictor Perevertkin             // requests the driver has made non-cancellable in preparation
37978a978a17SVictor Perevertkin             // for completion.
37988a978a17SVictor Perevertkin             //
37998a978a17SVictor Perevertkin             request->ADDREF(FXREQUEST_QUEUE_TAG);
38008a978a17SVictor Perevertkin 
38018a978a17SVictor Perevertkin             CancelForDriver(request);
38028a978a17SVictor Perevertkin 
38038a978a17SVictor Perevertkin             // The request could have been completed and released by the driver
38048a978a17SVictor Perevertkin         }
38058a978a17SVictor Perevertkin 
38068a978a17SVictor Perevertkin         //
38078a978a17SVictor Perevertkin         // Cleanup forward progress IRP list.
38088a978a17SVictor Perevertkin         //
38098a978a17SVictor Perevertkin         if (IsForwardProgressQueue()) {
38108a978a17SVictor Perevertkin             CancelIrps(&fwrIrpList);
38118a978a17SVictor Perevertkin         }
38128a978a17SVictor Perevertkin     }
38138a978a17SVictor Perevertkin 
38148a978a17SVictor Perevertkin     //
38158a978a17SVictor Perevertkin     // Since we set that no new requests may be dispatched,
38168a978a17SVictor Perevertkin     // if both m_Queue.GetRequestCount(), m_DriverIoCount == 0, and
38178a978a17SVictor Perevertkin     // m_Dispatch == 0, right now the queue is completely idle.
38188a978a17SVictor Perevertkin     //
38198a978a17SVictor Perevertkin 
38208a978a17SVictor Perevertkin     //
38218a978a17SVictor Perevertkin     // We check if our m_PurgeComplete callback is still set
38228a978a17SVictor Perevertkin     // since it may have been called by another thread when
38238a978a17SVictor Perevertkin     // we dropped the lock above
38248a978a17SVictor Perevertkin     //
38258a978a17SVictor Perevertkin     Lock(&irql);
38268a978a17SVictor Perevertkin     DispatchEvents(irql);
38278a978a17SVictor Perevertkin 
38288a978a17SVictor Perevertkin     //
38298a978a17SVictor Perevertkin     // If the driver registered an IdleComplete callback, and it was
38308a978a17SVictor Perevertkin     // not idle in the above check, it will be called when the final
38318a978a17SVictor Perevertkin     // callback handler from the device driver returns.
38328a978a17SVictor Perevertkin     //
38338a978a17SVictor Perevertkin     return STATUS_SUCCESS;
38348a978a17SVictor Perevertkin }
38358a978a17SVictor Perevertkin 
38368a978a17SVictor Perevertkin _Must_inspect_result_
38378a978a17SVictor Perevertkin NTSTATUS
QueueIdleSynchronously(__in BOOLEAN CancelRequests)38388a978a17SVictor Perevertkin FxIoQueue::QueueIdleSynchronously(
38398a978a17SVictor Perevertkin     __in BOOLEAN    CancelRequests
38408a978a17SVictor Perevertkin     )
38418a978a17SVictor Perevertkin /*++
38428a978a17SVictor Perevertkin 
38438a978a17SVictor Perevertkin Routine Description:
38448a978a17SVictor Perevertkin 
38458a978a17SVictor Perevertkin     Idle the Queue and wait for the driver-owned requests to complete.
38468a978a17SVictor Perevertkin 
38478a978a17SVictor Perevertkin Arguments:
38488a978a17SVictor Perevertkin 
38498a978a17SVictor Perevertkin     CancelRequests - If TRUE, functions tries to cancel outstanding requests.
38508a978a17SVictor Perevertkin 
38518a978a17SVictor Perevertkin Returns:
38528a978a17SVictor Perevertkin 
38538a978a17SVictor Perevertkin --*/
38548a978a17SVictor Perevertkin {
38558a978a17SVictor Perevertkin     NTSTATUS status;
38568a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_USER_MODE)
38578a978a17SVictor Perevertkin     MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
38588a978a17SVictor Perevertkin #else
38598a978a17SVictor Perevertkin     MxEvent eventOnStack;
38608a978a17SVictor Perevertkin     //
38618a978a17SVictor Perevertkin     // Note that initialize always succeeds in KM so return is not checked.
38628a978a17SVictor Perevertkin     //
38638a978a17SVictor Perevertkin     eventOnStack.Initialize(NotificationEvent, FALSE);
38648a978a17SVictor Perevertkin     MxEvent* event = eventOnStack.GetSelfPointer();
38658a978a17SVictor Perevertkin #endif
38668a978a17SVictor Perevertkin 
38678a978a17SVictor Perevertkin     status = QueueIdle(CancelRequests, _IdleComplete, event->GetSelfPointer());
38688a978a17SVictor Perevertkin 
38698a978a17SVictor Perevertkin     if(NT_SUCCESS(status)) {
38708a978a17SVictor Perevertkin 
38718a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
38728a978a17SVictor Perevertkin                         "Waiting for %d requests to complete "
38738a978a17SVictor Perevertkin                         "on WDFQUEUE 0x%p",
38748a978a17SVictor Perevertkin                         m_DriverIoCount,
38758a978a17SVictor Perevertkin                         GetObjectHandle());
38768a978a17SVictor Perevertkin 
38778a978a17SVictor Perevertkin         Mx::MxEnterCriticalRegion();
38788a978a17SVictor Perevertkin 
38798a978a17SVictor Perevertkin         GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
38808a978a17SVictor Perevertkin                 "waiting for queue to stop, WDFQUEUE", GetHandle(),
38818a978a17SVictor Perevertkin                 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
38828a978a17SVictor Perevertkin                 WaitSignalBreakUnderVerifier);
38838a978a17SVictor Perevertkin 
38848a978a17SVictor Perevertkin 
38858a978a17SVictor Perevertkin         Mx::MxLeaveCriticalRegion();
38868a978a17SVictor Perevertkin     }
38878a978a17SVictor Perevertkin 
38888a978a17SVictor Perevertkin     return status;
38898a978a17SVictor Perevertkin 
38908a978a17SVictor Perevertkin }
38918a978a17SVictor Perevertkin 
38928a978a17SVictor Perevertkin _Must_inspect_result_
38938a978a17SVictor Perevertkin NTSTATUS
QueuePurge(__in BOOLEAN CancelQueueRequests,__in BOOLEAN CancelDriverRequests,__in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,__in_opt WDFCONTEXT Context)38948a978a17SVictor Perevertkin FxIoQueue::QueuePurge(
38958a978a17SVictor Perevertkin     __in BOOLEAN                 CancelQueueRequests,
38968a978a17SVictor Perevertkin     __in BOOLEAN                 CancelDriverRequests,
38978a978a17SVictor Perevertkin     __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,
38988a978a17SVictor Perevertkin     __in_opt WDFCONTEXT              Context
38998a978a17SVictor Perevertkin     )
39008a978a17SVictor Perevertkin /*++
39018a978a17SVictor Perevertkin 
39028a978a17SVictor Perevertkin Routine Description:
39038a978a17SVictor Perevertkin 
39048a978a17SVictor Perevertkin     Purge the Queue.
39058a978a17SVictor Perevertkin 
39068a978a17SVictor Perevertkin      If CancelQueueRequests == TRUE, any requests in the
39078a978a17SVictor Perevertkin      Queue that have not been presented to the device driver are
39088a978a17SVictor Perevertkin      completed with STATUS_CANCELLED.
39098a978a17SVictor Perevertkin 
39108a978a17SVictor Perevertkin      If CancelDriverRequests == TRUE, any requests that the
39118a978a17SVictor Perevertkin      driver is operating on that are cancelable will have an
39128a978a17SVictor Perevertkin      I/O Cancel done on them.
39138a978a17SVictor Perevertkin 
39148a978a17SVictor Perevertkin Arguments:
39158a978a17SVictor Perevertkin 
39168a978a17SVictor Perevertkin Returns:
39178a978a17SVictor Perevertkin 
39188a978a17SVictor Perevertkin --*/
39198a978a17SVictor Perevertkin {
39208a978a17SVictor Perevertkin     FxRequest*  pRequest;
39218a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
39228a978a17SVictor Perevertkin     KIRQL irql;
39238a978a17SVictor Perevertkin     NTSTATUS status;
39248a978a17SVictor Perevertkin 
39258a978a17SVictor Perevertkin     Lock(&irql);
39268a978a17SVictor Perevertkin 
39278a978a17SVictor Perevertkin     //
39288a978a17SVictor Perevertkin     // If the Queue is deleted, there can't be any requests
39298a978a17SVictor Perevertkin     // to purge, and the queue is no longer executing its
39308a978a17SVictor Perevertkin     // event dispatch loop, so we would stop responding if we
39318a978a17SVictor Perevertkin     // registered now.
39328a978a17SVictor Perevertkin     //
39338a978a17SVictor Perevertkin     // We could try and silently succeed this, but if we do, we
39348a978a17SVictor Perevertkin     // must invoke the PurgeComplete callback, and without our
39358a978a17SVictor Perevertkin     // queue state machine excuting, we can not ensure any
39368a978a17SVictor Perevertkin     // callback constraints are handled such as locking, queueing
39378a978a17SVictor Perevertkin     // to passive level, etc. So we just fail to indicate to the
39388a978a17SVictor Perevertkin     // driver we *will not* be invoking its PurgeComplete function.
39398a978a17SVictor Perevertkin     //
39408a978a17SVictor Perevertkin     if (m_Deleted) {
39418a978a17SVictor Perevertkin         status = STATUS_DELETE_PENDING;
39428a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
39438a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p is already deleted %!STATUS!",
39448a978a17SVictor Perevertkin                             GetObjectHandle(), status);
39458a978a17SVictor Perevertkin         Unlock(irql);
39468a978a17SVictor Perevertkin 
39478a978a17SVictor Perevertkin         return status;
39488a978a17SVictor Perevertkin     }
39498a978a17SVictor Perevertkin 
39508a978a17SVictor Perevertkin     //
39518a978a17SVictor Perevertkin     // If a PurgeComplete callback is supplied, we must register it up
39528a978a17SVictor Perevertkin     // front since a transition empty could occur in another thread.
39538a978a17SVictor Perevertkin     //
39548a978a17SVictor Perevertkin     if (PurgeComplete != NULL) {
39558a978a17SVictor Perevertkin 
39568a978a17SVictor Perevertkin         //
39578a978a17SVictor Perevertkin         // Only one PurgeComplete callback can be outstanding
39588a978a17SVictor Perevertkin         // at a time per Queue
39598a978a17SVictor Perevertkin         //
39608a978a17SVictor Perevertkin         if (m_PurgeComplete.Method != NULL) {
39618a978a17SVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
39628a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
39638a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p already has a "
39648a978a17SVictor Perevertkin                                 "PurgeComplete callback registered 0x%p "
39658a978a17SVictor Perevertkin                                 "%!STATUS!", GetObjectHandle(),
39668a978a17SVictor Perevertkin                                 m_PurgeComplete.Method, status);
39678a978a17SVictor Perevertkin             Unlock(irql);
39688a978a17SVictor Perevertkin 
39698a978a17SVictor Perevertkin             return status;
39708a978a17SVictor Perevertkin         }
39718a978a17SVictor Perevertkin 
39728a978a17SVictor Perevertkin         m_PurgeComplete.Method = PurgeComplete;
39738a978a17SVictor Perevertkin         m_PurgeCompleteContext = Context;
39748a978a17SVictor Perevertkin     }
39758a978a17SVictor Perevertkin 
39768a978a17SVictor Perevertkin     // Clear accept requests
39778a978a17SVictor Perevertkin     SetState(FxIoQueueClearAcceptRequests);
39788a978a17SVictor Perevertkin 
39798a978a17SVictor Perevertkin     if (CancelQueueRequests && CancelDriverRequests &&
39808a978a17SVictor Perevertkin         FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
39818a978a17SVictor Perevertkin         //
39828a978a17SVictor Perevertkin         // Driver wants to abort/complete all queued request and cancel or
39838a978a17SVictor Perevertkin         // wait for all requests the driver is currently handling. Thus we must
39848a978a17SVictor Perevertkin         // prevent the driver from requeuing stale requests.
39858a978a17SVictor Perevertkin         // This flag is set here, and cleared when:
39868a978a17SVictor Perevertkin         //  (a) Driver doesn't own any more requests, or
39878a978a17SVictor Perevertkin         //  (b) the driver calls WdfIoQueueStart again (dispatch gate is opened).
39888a978a17SVictor Perevertkin         // When set, the framework automatically deletes  any request that the
39898a978a17SVictor Perevertkin         // driver requeues.
39908a978a17SVictor Perevertkin         // For compatibility we do this only for drivers v1.11 and above.
39918a978a17SVictor Perevertkin         //
39928a978a17SVictor Perevertkin         m_CancelDispatchedRequests = TRUE;
39938a978a17SVictor Perevertkin     }
39948a978a17SVictor Perevertkin 
39958a978a17SVictor Perevertkin     // Unlock queue lock
39968a978a17SVictor Perevertkin     Unlock(irql);
39978a978a17SVictor Perevertkin 
39988a978a17SVictor Perevertkin     if (CancelQueueRequests) {
39998a978a17SVictor Perevertkin                                                   #pragma warning(disable:4127)
40008a978a17SVictor Perevertkin         while (TRUE) {
40018a978a17SVictor Perevertkin                                                   #pragma warning(default:4127)
40028a978a17SVictor Perevertkin             //
40038a978a17SVictor Perevertkin             // Get the next FxRequest from the cancel safe queue
40048a978a17SVictor Perevertkin             //
40058a978a17SVictor Perevertkin             Lock(&irql);
40068a978a17SVictor Perevertkin             pRequest = FxRequest::GetNextRequest(&m_Queue);
40078a978a17SVictor Perevertkin             if (pRequest == NULL) {
40088a978a17SVictor Perevertkin                 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
40098a978a17SVictor Perevertkin                                     "All WDFQUEUE 0x%p requests cancelled",
40108a978a17SVictor Perevertkin                                     GetObjectHandle());
40118a978a17SVictor Perevertkin                 Unlock(irql);
40128a978a17SVictor Perevertkin                 break;
40138a978a17SVictor Perevertkin             }
40148a978a17SVictor Perevertkin 
40158a978a17SVictor Perevertkin             // Irp is not cancellable now
40168a978a17SVictor Perevertkin 
40178a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO,
40188a978a17SVictor Perevertkin                                 "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p",
40198a978a17SVictor Perevertkin                                 pRequest->GetHandle(),GetObjectHandle());
40208a978a17SVictor Perevertkin 
40218a978a17SVictor Perevertkin             //
40228a978a17SVictor Perevertkin             // We must add a reference since the CancelForQueue path
40238a978a17SVictor Perevertkin             // assumes we were on the FxIrpQueue with the extra reference
40248a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
40258a978a17SVictor Perevertkin 
40268a978a17SVictor Perevertkin             //
40278a978a17SVictor Perevertkin             // Mark the request as cancelled, place it on the cancel list,
40288a978a17SVictor Perevertkin             // and schedule the cancel event to the driver
40298a978a17SVictor Perevertkin             //
40308a978a17SVictor Perevertkin             CancelForQueue(pRequest, irql);
40318a978a17SVictor Perevertkin 
40328a978a17SVictor Perevertkin         }
40338a978a17SVictor Perevertkin     }
40348a978a17SVictor Perevertkin 
40358a978a17SVictor Perevertkin     if (CancelDriverRequests) {
40368a978a17SVictor Perevertkin 
40378a978a17SVictor Perevertkin         //
40388a978a17SVictor Perevertkin         // Walk the driver cancelable list cancelling
40398a978a17SVictor Perevertkin         // the requests.
40408a978a17SVictor Perevertkin         //
40418a978a17SVictor Perevertkin                                                   #pragma warning(disable:4127)
40428a978a17SVictor Perevertkin         while (TRUE) {
40438a978a17SVictor Perevertkin                                                   #pragma warning(default:4127)
40448a978a17SVictor Perevertkin             //
40458a978a17SVictor Perevertkin             // Get the next request of driver cancelable requests
40468a978a17SVictor Perevertkin             //
40478a978a17SVictor Perevertkin             Lock(&irql);
40488a978a17SVictor Perevertkin             pRequest = FxRequest::GetNextRequest(&m_DriverCancelable);
40498a978a17SVictor Perevertkin             if (pRequest == NULL) {
40508a978a17SVictor Perevertkin                 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
40518a978a17SVictor Perevertkin                                     "All driver cancellable requests cancelled "
40528a978a17SVictor Perevertkin                                     " in WDFQUEUE 0x%p",
40538a978a17SVictor Perevertkin                                     GetObjectHandle());
40548a978a17SVictor Perevertkin                 Unlock(irql);
40558a978a17SVictor Perevertkin                 break;
40568a978a17SVictor Perevertkin             }
40578a978a17SVictor Perevertkin 
40588a978a17SVictor Perevertkin             pRequest->m_Canceled = TRUE;
40598a978a17SVictor Perevertkin 
40608a978a17SVictor Perevertkin             Unlock(irql);
40618a978a17SVictor Perevertkin 
40628a978a17SVictor Perevertkin             //
40638a978a17SVictor Perevertkin             // If the driver follows the pattern of removing cancel status
40648a978a17SVictor Perevertkin             // from the request before completion, then there is no race
40658a978a17SVictor Perevertkin             // with this routine since we will not be able to retrieve any
40668a978a17SVictor Perevertkin             // requests the driver has made non-cancellable in preparation
40678a978a17SVictor Perevertkin             // for completion.
40688a978a17SVictor Perevertkin             //
40698a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
40708a978a17SVictor Perevertkin 
40718a978a17SVictor Perevertkin             CancelForDriver(pRequest);
40728a978a17SVictor Perevertkin 
40738a978a17SVictor Perevertkin             // The request could have been completed and released by the driver
40748a978a17SVictor Perevertkin         }
40758a978a17SVictor Perevertkin     }
40768a978a17SVictor Perevertkin 
40778a978a17SVictor Perevertkin     if (IsForwardProgressQueue()) {
40788a978a17SVictor Perevertkin         PurgeForwardProgressIrps(NULL);
40798a978a17SVictor Perevertkin     }
40808a978a17SVictor Perevertkin 
40818a978a17SVictor Perevertkin     //
40828a978a17SVictor Perevertkin     // Since we set that no new requests may be enqueued,
40838a978a17SVictor Perevertkin     // if both m_Queue.GetRequestCount() and m_DriverIoCount == 0 right
40848a978a17SVictor Perevertkin     // now the queue is completely purged.
40858a978a17SVictor Perevertkin     //
40868a978a17SVictor Perevertkin 
40878a978a17SVictor Perevertkin     //
40888a978a17SVictor Perevertkin     // We check if our m_PurgeComplete callback is still set
40898a978a17SVictor Perevertkin     // since it may have been called by another thread when
40908a978a17SVictor Perevertkin     // we dropped the lock above
40918a978a17SVictor Perevertkin     //
40928a978a17SVictor Perevertkin     Lock(&irql);
40938a978a17SVictor Perevertkin 
40948a978a17SVictor Perevertkin     DispatchEvents(irql);
40958a978a17SVictor Perevertkin 
40968a978a17SVictor Perevertkin     //
40978a978a17SVictor Perevertkin     // If the driver registered a PurgeComplete callback, and it was
40988a978a17SVictor Perevertkin     // not empty in the above check, it will be called when a
40998a978a17SVictor Perevertkin     // request complete from the device driver completes the
41008a978a17SVictor Perevertkin     // final request.
41018a978a17SVictor Perevertkin     //
41028a978a17SVictor Perevertkin     return STATUS_SUCCESS;
41038a978a17SVictor Perevertkin }
41048a978a17SVictor Perevertkin 
41058a978a17SVictor Perevertkin _Must_inspect_result_
41068a978a17SVictor Perevertkin NTSTATUS
QueuePurgeSynchronously()41078a978a17SVictor Perevertkin FxIoQueue::QueuePurgeSynchronously(
41088a978a17SVictor Perevertkin     )
41098a978a17SVictor Perevertkin /*++
41108a978a17SVictor Perevertkin 
41118a978a17SVictor Perevertkin Routine Description:
41128a978a17SVictor Perevertkin 
41138a978a17SVictor Perevertkin     Purge the queue and wait for it to complete.
41148a978a17SVictor Perevertkin     When this call returns, there are no requests in the queue or device
41158a978a17SVictor Perevertkin     driver and the queue state is set to reject new requests.
41168a978a17SVictor Perevertkin 
41178a978a17SVictor Perevertkin --*/
41188a978a17SVictor Perevertkin {
41198a978a17SVictor Perevertkin     NTSTATUS status;
41208a978a17SVictor Perevertkin 
41218a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_USER_MODE)
41228a978a17SVictor Perevertkin     MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
41238a978a17SVictor Perevertkin #else
41248a978a17SVictor Perevertkin     MxEvent eventOnStack;
41258a978a17SVictor Perevertkin     //
41268a978a17SVictor Perevertkin     // Note that initialize always succeeds in KM so return is not checked.
41278a978a17SVictor Perevertkin     //
41288a978a17SVictor Perevertkin     eventOnStack.Initialize(NotificationEvent, FALSE);
41298a978a17SVictor Perevertkin     MxEvent* event = eventOnStack.GetSelfPointer();
41308a978a17SVictor Perevertkin #endif
41318a978a17SVictor Perevertkin 
41328a978a17SVictor Perevertkin     status = QueuePurge(TRUE, TRUE, _PurgeComplete, event->GetSelfPointer());
41338a978a17SVictor Perevertkin 
41348a978a17SVictor Perevertkin     if(NT_SUCCESS(status)) {
41358a978a17SVictor Perevertkin 
41368a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
41378a978a17SVictor Perevertkin                         "Waiting for %d requests to complete "
41388a978a17SVictor Perevertkin                         "on WDFQUEUE 0x%p",
41398a978a17SVictor Perevertkin                         (m_DriverIoCount + m_Queue.GetRequestCount()),
41408a978a17SVictor Perevertkin                         GetObjectHandle());
41418a978a17SVictor Perevertkin 
41428a978a17SVictor Perevertkin         Mx::MxEnterCriticalRegion();
41438a978a17SVictor Perevertkin 
41448a978a17SVictor Perevertkin         GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
41458a978a17SVictor Perevertkin                 "waiting for queue to purge, WDFQUEUE", GetHandle(),
41468a978a17SVictor Perevertkin                 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
41478a978a17SVictor Perevertkin                 WaitSignalBreakUnderVerifier);
41488a978a17SVictor Perevertkin 
41498a978a17SVictor Perevertkin         Mx::MxLeaveCriticalRegion();
41508a978a17SVictor Perevertkin     }
41518a978a17SVictor Perevertkin 
41528a978a17SVictor Perevertkin     return status;
41538a978a17SVictor Perevertkin 
41548a978a17SVictor Perevertkin }
41558a978a17SVictor Perevertkin 
41568a978a17SVictor Perevertkin _Must_inspect_result_
41578a978a17SVictor Perevertkin NTSTATUS
QueueDrain(__in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,__in_opt WDFCONTEXT Context)41588a978a17SVictor Perevertkin FxIoQueue::QueueDrain(
41598a978a17SVictor Perevertkin     __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,
41608a978a17SVictor Perevertkin     __in_opt WDFCONTEXT              Context
41618a978a17SVictor Perevertkin     )
41628a978a17SVictor Perevertkin {
41638a978a17SVictor Perevertkin     //
41648a978a17SVictor Perevertkin     // We drain the queue by calling QueuePurge with CancelQueueRequests
41658a978a17SVictor Perevertkin     // and CancelDriverRequests == FALSE. The Queue will reject new
41668a978a17SVictor Perevertkin     //  requests, but allow the device driver to continue processing
41678a978a17SVictor Perevertkin     //  requests currently on the Queue. The DrainComplete callback is
41688a978a17SVictor Perevertkin     // invoked when there are no requests in Queue or device driver.
41698a978a17SVictor Perevertkin     //
41708a978a17SVictor Perevertkin 
41718a978a17SVictor Perevertkin     return QueuePurge(FALSE, FALSE, PurgeComplete, Context);
41728a978a17SVictor Perevertkin 
41738a978a17SVictor Perevertkin }
41748a978a17SVictor Perevertkin 
41758a978a17SVictor Perevertkin _Must_inspect_result_
41768a978a17SVictor Perevertkin NTSTATUS
QueueDrainSynchronously()41778a978a17SVictor Perevertkin FxIoQueue::QueueDrainSynchronously(
41788a978a17SVictor Perevertkin     )
41798a978a17SVictor Perevertkin /*++
41808a978a17SVictor Perevertkin 
41818a978a17SVictor Perevertkin Routine Description:
41828a978a17SVictor Perevertkin 
41838a978a17SVictor Perevertkin     Drain the queue and wait for it to complete.
41848a978a17SVictor Perevertkin     When this call returns, there are no requests in the queue or device
41858a978a17SVictor Perevertkin     driver and the queue state is set to reject new requests.
41868a978a17SVictor Perevertkin 
41878a978a17SVictor Perevertkin --*/
41888a978a17SVictor Perevertkin {
41898a978a17SVictor Perevertkin     NTSTATUS status;
41908a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_USER_MODE)
41918a978a17SVictor Perevertkin     MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
41928a978a17SVictor Perevertkin #else
41938a978a17SVictor Perevertkin     MxEvent eventOnStack;
41948a978a17SVictor Perevertkin     //
41958a978a17SVictor Perevertkin     // Note that initialize always succeeds in KM so return is not checked.
41968a978a17SVictor Perevertkin     //
41978a978a17SVictor Perevertkin     eventOnStack.Initialize(NotificationEvent, FALSE);
41988a978a17SVictor Perevertkin     MxEvent* event = eventOnStack.GetSelfPointer();
41998a978a17SVictor Perevertkin #endif
42008a978a17SVictor Perevertkin 
42018a978a17SVictor Perevertkin     status = QueueDrain(_PurgeComplete, event->GetSelfPointer());
42028a978a17SVictor Perevertkin 
42038a978a17SVictor Perevertkin     if(NT_SUCCESS(status)) {
42048a978a17SVictor Perevertkin 
42058a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
42068a978a17SVictor Perevertkin                         "Waiting for %d requests to complete "
42078a978a17SVictor Perevertkin                         "on WDFQUEUE 0x%p",
42088a978a17SVictor Perevertkin                         (m_DriverIoCount + m_Queue.GetRequestCount()),
42098a978a17SVictor Perevertkin                         GetObjectHandle());
42108a978a17SVictor Perevertkin 
42118a978a17SVictor Perevertkin         Mx::MxEnterCriticalRegion();
42128a978a17SVictor Perevertkin 
42138a978a17SVictor Perevertkin         GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
42148a978a17SVictor Perevertkin                 "waiting for queue to drain, WDFQUEUE", GetHandle(),
42158a978a17SVictor Perevertkin                 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
42168a978a17SVictor Perevertkin                 WaitSignalBreakUnderVerifier);
42178a978a17SVictor Perevertkin 
42188a978a17SVictor Perevertkin         Mx::MxLeaveCriticalRegion();
42198a978a17SVictor Perevertkin     }
42208a978a17SVictor Perevertkin 
42218a978a17SVictor Perevertkin     return status;
42228a978a17SVictor Perevertkin 
42238a978a17SVictor Perevertkin }
42248a978a17SVictor Perevertkin 
42258a978a17SVictor Perevertkin 
42268a978a17SVictor Perevertkin VOID
GetRequestCount(__out_opt PULONG pQueuedRequests,__out_opt PULONG pDriverPendingRequests)42278a978a17SVictor Perevertkin FxIoQueue::GetRequestCount(
42288a978a17SVictor Perevertkin     __out_opt PULONG pQueuedRequests,
42298a978a17SVictor Perevertkin     __out_opt PULONG pDriverPendingRequests
42308a978a17SVictor Perevertkin     )
42318a978a17SVictor Perevertkin /*++
42328a978a17SVictor Perevertkin 
42338a978a17SVictor Perevertkin Routine Description:
42348a978a17SVictor Perevertkin 
42358a978a17SVictor Perevertkin     Return the count of requests currently on the queue
42368a978a17SVictor Perevertkin     and owned by the driver.
42378a978a17SVictor Perevertkin 
42388a978a17SVictor Perevertkin Arguments:
42398a978a17SVictor Perevertkin 
42408a978a17SVictor Perevertkin Returns:
42418a978a17SVictor Perevertkin 
42428a978a17SVictor Perevertkin --*/
42438a978a17SVictor Perevertkin {
42448a978a17SVictor Perevertkin     if (pQueuedRequests != NULL) {
42458a978a17SVictor Perevertkin         *pQueuedRequests = m_Queue.GetRequestCount();
42468a978a17SVictor Perevertkin     }
42478a978a17SVictor Perevertkin 
42488a978a17SVictor Perevertkin     if (pDriverPendingRequests != NULL) {
42498a978a17SVictor Perevertkin         *pDriverPendingRequests = m_DriverIoCount;
42508a978a17SVictor Perevertkin     }
42518a978a17SVictor Perevertkin 
42528a978a17SVictor Perevertkin     return;
42538a978a17SVictor Perevertkin }
42548a978a17SVictor Perevertkin 
42558a978a17SVictor Perevertkin VOID
FlushByFileObject(__in MdFileObject FileObject)42568a978a17SVictor Perevertkin FxIoQueue::FlushByFileObject(
42578a978a17SVictor Perevertkin     __in MdFileObject FileObject
42588a978a17SVictor Perevertkin     )
42598a978a17SVictor Perevertkin /*++
42608a978a17SVictor Perevertkin 
42618a978a17SVictor Perevertkin Routine Description:
42628a978a17SVictor Perevertkin 
42638a978a17SVictor Perevertkin     Scan the queue and cancel all the requests that have
42648a978a17SVictor Perevertkin     the same fileobject as the input argument.
42658a978a17SVictor Perevertkin 
42668a978a17SVictor Perevertkin     This function is called when the IoPkg receives a
42678a978a17SVictor Perevertkin     IRP_MJ_CLEANUP requests.
42688a978a17SVictor Perevertkin 
42698a978a17SVictor Perevertkin     Additional reference is already taken on the object by the caller
42708a978a17SVictor Perevertkin     to prevent the queue from being deleted.
42718a978a17SVictor Perevertkin 
42728a978a17SVictor Perevertkin Return Value:
42738a978a17SVictor Perevertkin 
42748a978a17SVictor Perevertkin --*/
42758a978a17SVictor Perevertkin {
42768a978a17SVictor Perevertkin     FxRequest*  pRequest = NULL;
42778a978a17SVictor Perevertkin     NTSTATUS status;
42788a978a17SVictor Perevertkin     KIRQL irql;
42798a978a17SVictor Perevertkin 
42808a978a17SVictor Perevertkin     if (IsForwardProgressQueue()) {
42818a978a17SVictor Perevertkin         PurgeForwardProgressIrps(FileObject);
42828a978a17SVictor Perevertkin     }
42838a978a17SVictor Perevertkin 
42848a978a17SVictor Perevertkin     Lock(&irql);
42858a978a17SVictor Perevertkin 
42868a978a17SVictor Perevertkin                                             #pragma warning(disable:4127)
42878a978a17SVictor Perevertkin     while (TRUE) {
42888a978a17SVictor Perevertkin                                             #pragma warning(default:4127)
42898a978a17SVictor Perevertkin 
42908a978a17SVictor Perevertkin         //
42918a978a17SVictor Perevertkin         // Get the next FxRequest from the cancel safe queue
42928a978a17SVictor Perevertkin         //
42938a978a17SVictor Perevertkin         status = FxRequest::GetNextRequest(&m_Queue, FileObject, NULL, &pRequest);
42948a978a17SVictor Perevertkin         if(status == STATUS_NO_MORE_ENTRIES) {
42958a978a17SVictor Perevertkin             break;
42968a978a17SVictor Perevertkin         }
42978a978a17SVictor Perevertkin         if(!NT_SUCCESS(status)) {
42988a978a17SVictor Perevertkin             ASSERTMSG("GetNextRequest failed\n", FALSE);
42998a978a17SVictor Perevertkin             break;
43008a978a17SVictor Perevertkin         }
43018a978a17SVictor Perevertkin 
43028a978a17SVictor Perevertkin         //
43038a978a17SVictor Perevertkin         // We must add a reference since the CancelForQueue path
43048a978a17SVictor Perevertkin         // assumes we were on the FxIrpQueue with the extra reference
43058a978a17SVictor Perevertkin         //
43068a978a17SVictor Perevertkin         pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
43078a978a17SVictor Perevertkin 
43088a978a17SVictor Perevertkin         //
43098a978a17SVictor Perevertkin         // Mark the request as cancelled, place it on the cancel list,
43108a978a17SVictor Perevertkin         // and schedule the cancel event to the driver
43118a978a17SVictor Perevertkin         //
43128a978a17SVictor Perevertkin         CancelForQueue(pRequest, irql);
43138a978a17SVictor Perevertkin 
43148a978a17SVictor Perevertkin         //
43158a978a17SVictor Perevertkin         // Reacquire the lock because CancelForQueue visits the dispatch-loop
43168a978a17SVictor Perevertkin         // and releases the lock.
43178a978a17SVictor Perevertkin         //
43188a978a17SVictor Perevertkin         Lock(&irql);
43198a978a17SVictor Perevertkin     }
43208a978a17SVictor Perevertkin 
43218a978a17SVictor Perevertkin     DispatchEvents(irql);
43228a978a17SVictor Perevertkin 
43238a978a17SVictor Perevertkin     return;
43248a978a17SVictor Perevertkin 
43258a978a17SVictor Perevertkin }
43268a978a17SVictor Perevertkin 
43278a978a17SVictor Perevertkin _Releases_lock_(this->m_SpinLock.m_Lock)
43288a978a17SVictor Perevertkin VOID
CancelForQueue(__in FxRequest * pRequest,__in __drv_restoresIRQL KIRQL PreviousIrql)43298a978a17SVictor Perevertkin FxIoQueue::CancelForQueue(
43308a978a17SVictor Perevertkin     __in FxRequest* pRequest,
43318a978a17SVictor Perevertkin     __in __drv_restoresIRQL KIRQL PreviousIrql
43328a978a17SVictor Perevertkin     )
43338a978a17SVictor Perevertkin /*++
43348a978a17SVictor Perevertkin 
43358a978a17SVictor Perevertkin     Routine Description:
43368a978a17SVictor Perevertkin 
43378a978a17SVictor Perevertkin     This routine performs the actions when notified of a cancel
43388a978a17SVictor Perevertkin      on a request that has not been presented to the driver
43398a978a17SVictor Perevertkin 
43408a978a17SVictor Perevertkin     Return Value:
43418a978a17SVictor Perevertkin 
43428a978a17SVictor Perevertkin     NTSTATUS
43438a978a17SVictor Perevertkin 
43448a978a17SVictor Perevertkin --*/
43458a978a17SVictor Perevertkin {
43468a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
43478a978a17SVictor Perevertkin     FxRequestCompletionState oldState;
43488a978a17SVictor Perevertkin 
43498a978a17SVictor Perevertkin     // This is not an error, but want to make sure cancel testing works
43508a978a17SVictor Perevertkin     if (FxDriverGlobals->FxVerifierOn) {
43518a978a17SVictor Perevertkin 
43528a978a17SVictor Perevertkin         // Clear cancellable status, otherwise verifier in FxRequest::Complete will complain
43538a978a17SVictor Perevertkin         pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
43548a978a17SVictor Perevertkin 
43558a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO,
43568a978a17SVictor Perevertkin                             "WDFREQUEST 0x%p "
43578a978a17SVictor Perevertkin                             "was cancelled while on WDFQUEUE 0x%p",
43588a978a17SVictor Perevertkin                             pRequest->GetHandle(),GetObjectHandle());
43598a978a17SVictor Perevertkin     }
43608a978a17SVictor Perevertkin 
43618a978a17SVictor Perevertkin     pRequest->m_Canceled = TRUE;
43628a978a17SVictor Perevertkin 
43638a978a17SVictor Perevertkin     pRequest->MarkRemovedFromIrpQueue();
43648a978a17SVictor Perevertkin 
43658a978a17SVictor Perevertkin     //
43668a978a17SVictor Perevertkin     // Drop the extra reference taken when it was added to the queue
43678a978a17SVictor Perevertkin     // because the request is now leaving the queue.
43688a978a17SVictor Perevertkin     //
43698a978a17SVictor Perevertkin     pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
43708a978a17SVictor Perevertkin 
43718a978a17SVictor Perevertkin     //
43728a978a17SVictor Perevertkin     // If the driver has registered m_CanceledOnQueue callback, and if
43738a978a17SVictor Perevertkin     // the request was ever presented to the driver then we need to
43748a978a17SVictor Perevertkin     // notify the driver
43758a978a17SVictor Perevertkin     //
43768a978a17SVictor Perevertkin     if(m_IoCanceledOnQueue.Method && pRequest->m_Presented) {
43778a978a17SVictor Perevertkin 
43788a978a17SVictor Perevertkin         //
43798a978a17SVictor Perevertkin         // Set the state to indicate the request has come from a queue.
43808a978a17SVictor Perevertkin         //
43818a978a17SVictor Perevertkin         oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
43828a978a17SVictor Perevertkin         ASSERT(oldState == FxRequestCompletionStateNone);
43838a978a17SVictor Perevertkin         UNREFERENCED_PARAMETER(oldState);
43848a978a17SVictor Perevertkin 
43858a978a17SVictor Perevertkin         // Insert it on the driver owned list
43868a978a17SVictor Perevertkin         InsertInDriverOwnedList(pRequest);
43878a978a17SVictor Perevertkin 
43888a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
43898a978a17SVictor Perevertkin             ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0);
43908a978a17SVictor Perevertkin             pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
43918a978a17SVictor Perevertkin         }
43928a978a17SVictor Perevertkin 
43938a978a17SVictor Perevertkin         //
43948a978a17SVictor Perevertkin         // Also insert the request in to m_CanceledOnQueueList so
43958a978a17SVictor Perevertkin         // that we can notify the driver when we visit the DispatchEvents
43968a978a17SVictor Perevertkin         //
43978a978a17SVictor Perevertkin         InsertTailList(&m_CanceledOnQueueList, pRequest->GetListEntry(FxListEntryQueueOwned));
43988a978a17SVictor Perevertkin 
43998a978a17SVictor Perevertkin         //
44008a978a17SVictor Perevertkin         // Release the reference taken in the call to SetCompletionState.
44018a978a17SVictor Perevertkin         //
44028a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_STATE_TAG);
44038a978a17SVictor Perevertkin     } else {
44048a978a17SVictor Perevertkin 
44058a978a17SVictor Perevertkin         Unlock(PreviousIrql);
44068a978a17SVictor Perevertkin 
44078a978a17SVictor Perevertkin         // Its gone from our list, so complete it cancelled
44088a978a17SVictor Perevertkin         pRequest->CompleteWithInformation(STATUS_CANCELLED, 0);
44098a978a17SVictor Perevertkin 
44108a978a17SVictor Perevertkin         // Dereference the request objects final reference
44118a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
44128a978a17SVictor Perevertkin 
44138a978a17SVictor Perevertkin         Lock(&PreviousIrql);
44148a978a17SVictor Perevertkin     }
44158a978a17SVictor Perevertkin 
44168a978a17SVictor Perevertkin     // This may have caused the queue to be emptied
44178a978a17SVictor Perevertkin     DispatchInternalEvents(PreviousIrql);
44188a978a17SVictor Perevertkin 
44198a978a17SVictor Perevertkin     return;
44208a978a17SVictor Perevertkin }
44218a978a17SVictor Perevertkin 
44228a978a17SVictor Perevertkin VOID
_IrpCancelForQueue(__in FxIrpQueue * IrpQueue,__in MdIrp Irp,__in PMdIoCsqIrpContext CsqContext,__in KIRQL Irql)44238a978a17SVictor Perevertkin FxIoQueue::_IrpCancelForQueue(
44248a978a17SVictor Perevertkin     __in FxIrpQueue* IrpQueue,
44258a978a17SVictor Perevertkin     __in MdIrp        Irp,
44268a978a17SVictor Perevertkin     __in PMdIoCsqIrpContext CsqContext,
44278a978a17SVictor Perevertkin     __in KIRQL Irql
44288a978a17SVictor Perevertkin     )
44298a978a17SVictor Perevertkin /*++
44308a978a17SVictor Perevertkin 
44318a978a17SVictor Perevertkin Routine Description:
44328a978a17SVictor Perevertkin     This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an
44338a978a17SVictor Perevertkin     I/O cancellation on the main (pre driver) Queue.
44348a978a17SVictor Perevertkin 
44358a978a17SVictor Perevertkin     Note this callback is called with the queue lock held.
44368a978a17SVictor Perevertkin 
44378a978a17SVictor Perevertkin Arguments:
44388a978a17SVictor Perevertkin     IrpQueue - Queue the request was on
44398a978a17SVictor Perevertkin 
44408a978a17SVictor Perevertkin     Irp - the irp being cancelled
44418a978a17SVictor Perevertkin 
44428a978a17SVictor Perevertkin     CsqContext - the context associated with the irp
44438a978a17SVictor Perevertkin 
44448a978a17SVictor Perevertkin Return Value:
44458a978a17SVictor Perevertkin     None
44468a978a17SVictor Perevertkin 
44478a978a17SVictor Perevertkin   --*/
44488a978a17SVictor Perevertkin {
44498a978a17SVictor Perevertkin     FxIoQueue* ioQueue;
44508a978a17SVictor Perevertkin     FxRequest* pRequest;
44518a978a17SVictor Perevertkin 
44528a978a17SVictor Perevertkin     ioQueue = CONTAINING_RECORD(IrpQueue, FxIoQueue, m_Queue);
44538a978a17SVictor Perevertkin     pRequest = FxRequest::RetrieveFromCsqContext(CsqContext);
44548a978a17SVictor Perevertkin 
44558a978a17SVictor Perevertkin     //
44568a978a17SVictor Perevertkin     // Must reference the queue since this could be the final
44578a978a17SVictor Perevertkin     // request on a deleting queue
44588a978a17SVictor Perevertkin     //
44598a978a17SVictor Perevertkin     ioQueue->ADDREF(Irp);
44608a978a17SVictor Perevertkin 
44618a978a17SVictor Perevertkin     //
44628a978a17SVictor Perevertkin     // We cannot drop the lock here because we may have to insert the
44638a978a17SVictor Perevertkin     // request in the driver owned list if the driver has registered
44648a978a17SVictor Perevertkin     // for canceled-on-queue callback. If we drop the lock and if the request
44658a978a17SVictor Perevertkin     // happens to be last request, the delete will run thru and put
44668a978a17SVictor Perevertkin     // the state of the queue to deleted state and prevent further dispatching
44678a978a17SVictor Perevertkin     // of requests.
44688a978a17SVictor Perevertkin     //
44698a978a17SVictor Perevertkin     ioQueue->CancelForQueue(pRequest, Irql);
44708a978a17SVictor Perevertkin 
44718a978a17SVictor Perevertkin     ioQueue->RELEASE(Irp);
44728a978a17SVictor Perevertkin }
44738a978a17SVictor Perevertkin 
44748a978a17SVictor Perevertkin VOID
FX_VF_METHOD(FxIoQueue,VerifyValidateCompletedRequest)44758a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyValidateCompletedRequest)(
44768a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
44778a978a17SVictor Perevertkin     _In_ FxRequest* Request
44788a978a17SVictor Perevertkin     )
44798a978a17SVictor Perevertkin {
44808a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(FxDriverGlobals);
44818a978a17SVictor Perevertkin 
44828a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
44838a978a17SVictor Perevertkin 
44848a978a17SVictor Perevertkin     PLIST_ENTRY pEntry;
44858a978a17SVictor Perevertkin     KIRQL irql;
44868a978a17SVictor Perevertkin 
44878a978a17SVictor Perevertkin     Request->Lock(&irql);
44888a978a17SVictor Perevertkin 
44898a978a17SVictor Perevertkin     (VOID) Request->VerifyRequestIsDriverOwned(FxDriverGlobals);
44908a978a17SVictor Perevertkin     Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
44918a978a17SVictor Perevertkin 
44928a978a17SVictor Perevertkin     Request->Unlock(irql);
44938a978a17SVictor Perevertkin 
44948a978a17SVictor Perevertkin     // Driver no longer owns it once completed
44958a978a17SVictor Perevertkin 
44968a978a17SVictor Perevertkin     // Request can't be on a cancel list
44978a978a17SVictor Perevertkin     pEntry = Request->GetListEntry(FxListEntryQueueOwned);
44988a978a17SVictor Perevertkin     if( !IsListEmpty(pEntry) ) {
44998a978a17SVictor Perevertkin         DoTraceLevelMessage(
45008a978a17SVictor Perevertkin             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
45018a978a17SVictor Perevertkin             "WDFREQUEST 0x%p is on a cancellation list for WDFQUEUE 0x%p",
45028a978a17SVictor Perevertkin             Request->GetHandle(), GetObjectHandle());
45038a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(GetDriverGlobals());
45048a978a17SVictor Perevertkin     }
45058a978a17SVictor Perevertkin }
45068a978a17SVictor Perevertkin 
45078a978a17SVictor Perevertkin VOID
FX_VF_METHOD(FxIoQueue,VerifyCancelForDriver)45088a978a17SVictor Perevertkin FX_VF_METHOD(FxIoQueue, VerifyCancelForDriver) (
45098a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
45108a978a17SVictor Perevertkin     _In_ FxRequest* Request
45118a978a17SVictor Perevertkin     )
45128a978a17SVictor Perevertkin {
45138a978a17SVictor Perevertkin     PLIST_ENTRY pEntry;
45148a978a17SVictor Perevertkin 
45158a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
45168a978a17SVictor Perevertkin 
45178a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO,
45188a978a17SVictor Perevertkin                         "WDFREQUEST 0x%p "
45198a978a17SVictor Perevertkin                         "was cancelled in driver for WDFQUEUE 0x%p",
45208a978a17SVictor Perevertkin                         Request->GetHandle(), GetObjectHandle());
45218a978a17SVictor Perevertkin 
45228a978a17SVictor Perevertkin     // Verifier code assures this is available to the cancel processing
45238a978a17SVictor Perevertkin     pEntry = Request->GetListEntry(FxListEntryQueueOwned);
45248a978a17SVictor Perevertkin     if (!IsListEmpty(pEntry)) {
45258a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
45268a978a17SVictor Perevertkin                             "WDFREQUEST 0x%p is "
45278a978a17SVictor Perevertkin                             "already on list, FxRequest::m_ListEntry is busy!, "
45288a978a17SVictor Perevertkin                             "WDFQUEUE 0x%p",
45298a978a17SVictor Perevertkin                             Request->GetHandle(), GetObjectHandle());
45308a978a17SVictor Perevertkin         FxVerifierDbgBreakPoint(FxDriverGlobals);
45318a978a17SVictor Perevertkin     }
45328a978a17SVictor Perevertkin }
45338a978a17SVictor Perevertkin 
45348a978a17SVictor Perevertkin VOID
CancelForDriver(__in FxRequest * pRequest)45358a978a17SVictor Perevertkin FxIoQueue::CancelForDriver(
45368a978a17SVictor Perevertkin     __in FxRequest* pRequest
45378a978a17SVictor Perevertkin     )
45388a978a17SVictor Perevertkin /*++
45398a978a17SVictor Perevertkin 
45408a978a17SVictor Perevertkin Routine Description:
45418a978a17SVictor Perevertkin 
45428a978a17SVictor Perevertkin     This is called when a driver-owned cancelable request is canceled.
45438a978a17SVictor Perevertkin     This routine will add the request to m_Canceled list so that the
45448a978a17SVictor Perevertkin     dispatcher and call the driver cancel-routine to notify the driver.
45458a978a17SVictor Perevertkin 
45468a978a17SVictor Perevertkin     Queue lock is not held.
45478a978a17SVictor Perevertkin 
45488a978a17SVictor Perevertkin Arguments:
45498a978a17SVictor Perevertkin 
45508a978a17SVictor Perevertkin     pRequest - is a driver owned cancelable request.
45518a978a17SVictor Perevertkin 
45528a978a17SVictor Perevertkin Return Value:
45538a978a17SVictor Perevertkin 
45548a978a17SVictor Perevertkin --*/
45558a978a17SVictor Perevertkin {
45568a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
45578a978a17SVictor Perevertkin     KIRQL irql;
45588a978a17SVictor Perevertkin 
45598a978a17SVictor Perevertkin     // This is not an error, but want to make sure cancel testing works
45608a978a17SVictor Perevertkin     VerifyCancelForDriver(FxDriverGlobals, pRequest);
45618a978a17SVictor Perevertkin 
45628a978a17SVictor Perevertkin     //
45638a978a17SVictor Perevertkin     // We are called with no locks held, but
45648a978a17SVictor Perevertkin     // can be in arbitrary thread context from
45658a978a17SVictor Perevertkin     // a cancel occuring from another driver within
45668a978a17SVictor Perevertkin     // a driver stack.
45678a978a17SVictor Perevertkin     //
45688a978a17SVictor Perevertkin 
45698a978a17SVictor Perevertkin     //
45708a978a17SVictor Perevertkin     // The Csq has removed this request from the driver pending
45718a978a17SVictor Perevertkin     // queue, and it no longer has a cancel function if the
45728a978a17SVictor Perevertkin     // driver does not accept the cancel right now.
45738a978a17SVictor Perevertkin     //
45748a978a17SVictor Perevertkin     // When callside eventually goes to remove it from the queue
45758a978a17SVictor Perevertkin     // by CsqContext, the Csq's will return NULL.
45768a978a17SVictor Perevertkin     //
45778a978a17SVictor Perevertkin     // Irp and FxRequest is still valid until the driver calls
45788a978a17SVictor Perevertkin     // WdfRequestComplete either as a result of this cancel
45798a978a17SVictor Perevertkin     // callback, or at its leasure if it chooses to ignore it.
45808a978a17SVictor Perevertkin     //
45818a978a17SVictor Perevertkin     // The insert of FxRequest onto the FxIrpQueue took out a
45828a978a17SVictor Perevertkin     // reference, and when an IRP gets cancelled, we are responsible
45838a978a17SVictor Perevertkin     // for this final dereference after calling into the driver.
45848a978a17SVictor Perevertkin     //
45858a978a17SVictor Perevertkin 
45868a978a17SVictor Perevertkin     //
45878a978a17SVictor Perevertkin     // Cancellations are dispatched as events to the device driver
45888a978a17SVictor Perevertkin     // using the standard DispatchEvents processing loop. In order
45898a978a17SVictor Perevertkin     // to support this, we must defer it by linking this request
45908a978a17SVictor Perevertkin     // into a list of cancelled requests.
45918a978a17SVictor Perevertkin     //
45928a978a17SVictor Perevertkin     // The requests will be removed from this list and cancel notified
45938a978a17SVictor Perevertkin     // to the device driver by the processing loop.
45948a978a17SVictor Perevertkin     //
45958a978a17SVictor Perevertkin 
45968a978a17SVictor Perevertkin     pRequest->MarkRemovedFromIrpQueue();
45978a978a17SVictor Perevertkin 
45988a978a17SVictor Perevertkin     //
45998a978a17SVictor Perevertkin     // Queue it on the cancelled list
46008a978a17SVictor Perevertkin     //
46018a978a17SVictor Perevertkin     Lock(&irql);
46028a978a17SVictor Perevertkin 
46038a978a17SVictor Perevertkin     InsertTailList(&m_Cancelled, pRequest->GetListEntry(FxListEntryQueueOwned));
46048a978a17SVictor Perevertkin 
46058a978a17SVictor Perevertkin     //
46068a978a17SVictor Perevertkin     // Visit the event dispatcher
46078a978a17SVictor Perevertkin     //
46088a978a17SVictor Perevertkin     DispatchInternalEvents(irql);
46098a978a17SVictor Perevertkin 
46108a978a17SVictor Perevertkin     return;
46118a978a17SVictor Perevertkin }
46128a978a17SVictor Perevertkin 
46138a978a17SVictor Perevertkin VOID
_IrpCancelForDriver(__in FxIrpQueue * IrpQueue,__in MdIrp Irp,__in PMdIoCsqIrpContext CsqContext,__in KIRQL Irql)46148a978a17SVictor Perevertkin FxIoQueue::_IrpCancelForDriver(
46158a978a17SVictor Perevertkin     __in FxIrpQueue* IrpQueue,
46168a978a17SVictor Perevertkin     __in MdIrp        Irp,
46178a978a17SVictor Perevertkin     __in PMdIoCsqIrpContext CsqContext,
46188a978a17SVictor Perevertkin     __in KIRQL Irql
46198a978a17SVictor Perevertkin     )
46208a978a17SVictor Perevertkin /*++
46218a978a17SVictor Perevertkin 
46228a978a17SVictor Perevertkin Routine Description:
46238a978a17SVictor Perevertkin     This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an
46248a978a17SVictor Perevertkin     I/O cancellation on a driver owned request (driver queue)
46258a978a17SVictor Perevertkin 
46268a978a17SVictor Perevertkin     Note this callback is called with the queue lock held.
46278a978a17SVictor Perevertkin 
46288a978a17SVictor Perevertkin Arguments:
46298a978a17SVictor Perevertkin     IrpQueue - Queue the request was on
46308a978a17SVictor Perevertkin 
46318a978a17SVictor Perevertkin     Irp - the irp being cancelled
46328a978a17SVictor Perevertkin 
46338a978a17SVictor Perevertkin     CsqContext - the context associated with the irp
46348a978a17SVictor Perevertkin 
46358a978a17SVictor Perevertkin 
46368a978a17SVictor Perevertkin Return Value:
46378a978a17SVictor Perevertkin     None
46388a978a17SVictor Perevertkin 
46398a978a17SVictor Perevertkin   --*/
46408a978a17SVictor Perevertkin {
46418a978a17SVictor Perevertkin     FxIoQueue* ioQueue;
46428a978a17SVictor Perevertkin     FxRequest* pRequest;
46438a978a17SVictor Perevertkin 
46448a978a17SVictor Perevertkin     ioQueue = CONTAINING_RECORD(IrpQueue, FxIoQueue, m_DriverCancelable);
46458a978a17SVictor Perevertkin     pRequest = FxRequest::RetrieveFromCsqContext(CsqContext);
46468a978a17SVictor Perevertkin 
46478a978a17SVictor Perevertkin     pRequest->m_Canceled = TRUE;
46488a978a17SVictor Perevertkin 
46498a978a17SVictor Perevertkin     //
46508a978a17SVictor Perevertkin     // Must reference the queue since this could be the final
46518a978a17SVictor Perevertkin     // request on a deleting queue.
46528a978a17SVictor Perevertkin     //
46538a978a17SVictor Perevertkin     ioQueue->ADDREF(Irp);
46548a978a17SVictor Perevertkin 
46558a978a17SVictor Perevertkin     //
46568a978a17SVictor Perevertkin     // We can drop the lock because this request is a driver owned request and
46578a978a17SVictor Perevertkin     // it is tracked by m_DriverIoCount. As a result delete will be blocked
46588a978a17SVictor Perevertkin     // until the request is completed.
46598a978a17SVictor Perevertkin     //
46608a978a17SVictor Perevertkin     ioQueue->Unlock(Irql);
46618a978a17SVictor Perevertkin 
46628a978a17SVictor Perevertkin     ioQueue->CancelForDriver(pRequest);
46638a978a17SVictor Perevertkin 
46648a978a17SVictor Perevertkin     ioQueue->RELEASE(Irp);
46658a978a17SVictor Perevertkin }
46668a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)46678a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
46688a978a17SVictor Perevertkin VOID
46698a978a17SVictor Perevertkin FxIoQueue::ProcessIdleComplete(
46708a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
46718a978a17SVictor Perevertkin     )
46728a978a17SVictor Perevertkin /*++
46738a978a17SVictor Perevertkin 
46748a978a17SVictor Perevertkin Routine Description:
46758a978a17SVictor Perevertkin 
46768a978a17SVictor Perevertkin     Handle IdleComplete.
46778a978a17SVictor Perevertkin     Calls back the driver if conditions are met.
46788a978a17SVictor Perevertkin     Called with Queue lock held, but can drop and re-acquire
46798a978a17SVictor Perevertkin     it when delivering the event callback to the device driver.
46808a978a17SVictor Perevertkin 
46818a978a17SVictor Perevertkin Arguments:
46828a978a17SVictor Perevertkin     IrpQueue - Queue the request was on
46838a978a17SVictor Perevertkin 
46848a978a17SVictor Perevertkin     Irp - the irp being cancelled
46858a978a17SVictor Perevertkin 
46868a978a17SVictor Perevertkin     CsqContext - the context associated with the irp
46878a978a17SVictor Perevertkin 
46888a978a17SVictor Perevertkin Return Value:
46898a978a17SVictor Perevertkin     None
46908a978a17SVictor Perevertkin 
46918a978a17SVictor Perevertkin   --*/
46928a978a17SVictor Perevertkin {
46938a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
46948a978a17SVictor Perevertkin     WDFCONTEXT              ctx;
46958a978a17SVictor Perevertkin     FxIoQueueIoState       callback;
46968a978a17SVictor Perevertkin 
46978a978a17SVictor Perevertkin 
46988a978a17SVictor Perevertkin     callback = m_IdleComplete;
46998a978a17SVictor Perevertkin     ctx = m_IdleCompleteContext;
47008a978a17SVictor Perevertkin 
47018a978a17SVictor Perevertkin     m_IdleComplete.Method = NULL;
47028a978a17SVictor Perevertkin     m_IdleCompleteContext = NULL;
47038a978a17SVictor Perevertkin 
47048a978a17SVictor Perevertkin     Unlock(*PreviousIrql);
47058a978a17SVictor Perevertkin 
47068a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
47078a978a17SVictor Perevertkin                         "WDFQUEUE 0x%p is idle, calling driver callback",
47088a978a17SVictor Perevertkin                         GetHandle());
47098a978a17SVictor Perevertkin 
47108a978a17SVictor Perevertkin     // Notify driver by callback
47118a978a17SVictor Perevertkin     if (callback.Method != NULL) {
47128a978a17SVictor Perevertkin         callback.Invoke(GetHandle(), ctx);
47138a978a17SVictor Perevertkin     }
47148a978a17SVictor Perevertkin 
47158a978a17SVictor Perevertkin     Lock(PreviousIrql);
47168a978a17SVictor Perevertkin 
47178a978a17SVictor Perevertkin     return;
47188a978a17SVictor Perevertkin }
47198a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)47208a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
47218a978a17SVictor Perevertkin VOID
47228a978a17SVictor Perevertkin FxIoQueue::ProcessPurgeComplete(
47238a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
47248a978a17SVictor Perevertkin     )
47258a978a17SVictor Perevertkin /*++
47268a978a17SVictor Perevertkin 
47278a978a17SVictor Perevertkin Routine Description:
47288a978a17SVictor Perevertkin 
47298a978a17SVictor Perevertkin 
47308a978a17SVictor Perevertkin     Handle PurgeComplete.
47318a978a17SVictor Perevertkin 
47328a978a17SVictor Perevertkin     Calls back the driver if conditions are met.
47338a978a17SVictor Perevertkin 
47348a978a17SVictor Perevertkin     Called with Queue lock held, but can drop and re-acquire
47358a978a17SVictor Perevertkin     it when delivering the event callback to the device driver.
47368a978a17SVictor Perevertkin 
47378a978a17SVictor Perevertkin 
47388a978a17SVictor Perevertkin Arguments:
47398a978a17SVictor Perevertkin 
47408a978a17SVictor Perevertkin Return Value:
47418a978a17SVictor Perevertkin     None
47428a978a17SVictor Perevertkin 
47438a978a17SVictor Perevertkin   --*/
47448a978a17SVictor Perevertkin {
47458a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
47468a978a17SVictor Perevertkin     WDFCONTEXT              ctx;
47478a978a17SVictor Perevertkin     FxIoQueueIoState       callback;
47488a978a17SVictor Perevertkin 
47498a978a17SVictor Perevertkin     callback = m_PurgeComplete;
47508a978a17SVictor Perevertkin     ctx = m_PurgeCompleteContext;
47518a978a17SVictor Perevertkin 
47528a978a17SVictor Perevertkin     m_PurgeComplete.Method = NULL;
47538a978a17SVictor Perevertkin     m_PurgeCompleteContext = NULL;
47548a978a17SVictor Perevertkin 
47558a978a17SVictor Perevertkin     Unlock(*PreviousIrql);
47568a978a17SVictor Perevertkin 
47578a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
47588a978a17SVictor Perevertkin                         "WDFQUEUE 0x%p is purged, calling driver callback",
47598a978a17SVictor Perevertkin                         GetObjectHandle());
47608a978a17SVictor Perevertkin 
47618a978a17SVictor Perevertkin     // Notify driver by callback
47628a978a17SVictor Perevertkin     if (callback.Method != NULL) {
47638a978a17SVictor Perevertkin         callback.Invoke(GetHandle(), ctx);
47648a978a17SVictor Perevertkin     }
47658a978a17SVictor Perevertkin 
47668a978a17SVictor Perevertkin     Lock(PreviousIrql);
47678a978a17SVictor Perevertkin 
47688a978a17SVictor Perevertkin     return;
47698a978a17SVictor Perevertkin }
47708a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)47718a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
47728a978a17SVictor Perevertkin VOID
47738a978a17SVictor Perevertkin FxIoQueue::ProcessReadyNotify(
47748a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
47758a978a17SVictor Perevertkin     )
47768a978a17SVictor Perevertkin /*++
47778a978a17SVictor Perevertkin 
47788a978a17SVictor Perevertkin Routine Description:
47798a978a17SVictor Perevertkin 
47808a978a17SVictor Perevertkin     Callback the driver for a Queue ready notify
47818a978a17SVictor Perevertkin     Called with the Queue lock held, and may release
47828a978a17SVictor Perevertkin     and re-acquire it in calling back the driver
47838a978a17SVictor Perevertkin 
47848a978a17SVictor Perevertkin Arguments:
47858a978a17SVictor Perevertkin 
47868a978a17SVictor Perevertkin Return Value:
47878a978a17SVictor Perevertkin     None
47888a978a17SVictor Perevertkin 
47898a978a17SVictor Perevertkin   --*/
47908a978a17SVictor Perevertkin {
47918a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
47928a978a17SVictor Perevertkin     WDFCONTEXT              ctx;
47938a978a17SVictor Perevertkin     FxIoQueueIoState       callback;
47948a978a17SVictor Perevertkin 
47958a978a17SVictor Perevertkin     //
47968a978a17SVictor Perevertkin     // A callback to the driver "consumes" the notification.
47978a978a17SVictor Perevertkin     // Since we drop the lock when we call the driver, there is
47988a978a17SVictor Perevertkin     // a chance for the queue to be stopped or powered-off before
47998a978a17SVictor Perevertkin     // the driver tries to retrieve the request. So make sure
48008a978a17SVictor Perevertkin     // to set this flag when you power-on or start the queue to
48018a978a17SVictor Perevertkin     // avoid abandoning the requests in the queue.
48028a978a17SVictor Perevertkin     //
48038a978a17SVictor Perevertkin     m_TransitionFromEmpty = FALSE;
48048a978a17SVictor Perevertkin 
48058a978a17SVictor Perevertkin     //
48068a978a17SVictor Perevertkin     // Save a local copy since another thread could
48078a978a17SVictor Perevertkin     // cancel the ready notification out from under us
48088a978a17SVictor Perevertkin     // when we drop the lock
48098a978a17SVictor Perevertkin     //
48108a978a17SVictor Perevertkin     callback = m_ReadyNotify;
48118a978a17SVictor Perevertkin 
48128a978a17SVictor Perevertkin     ctx  = m_ReadyNotifyContext;
48138a978a17SVictor Perevertkin 
48148a978a17SVictor Perevertkin     Unlock(*PreviousIrql);
48158a978a17SVictor Perevertkin 
48168a978a17SVictor Perevertkin     if (callback.Method != NULL) {
48178a978a17SVictor Perevertkin         callback.Invoke(GetHandle(), ctx);
48188a978a17SVictor Perevertkin     }
48198a978a17SVictor Perevertkin     else {
48208a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
48218a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
48228a978a17SVictor Perevertkin                                 "ReadyNotify notify method is NULL "
48238a978a17SVictor Perevertkin                                 "on WDFQUEUE 0x%p", GetObjectHandle());
48248a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(FxDriverGlobals);
48258a978a17SVictor Perevertkin         }
48268a978a17SVictor Perevertkin     }
48278a978a17SVictor Perevertkin 
48288a978a17SVictor Perevertkin     Lock(PreviousIrql);
48298a978a17SVictor Perevertkin 
48308a978a17SVictor Perevertkin     return;
48318a978a17SVictor Perevertkin }
48328a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)48338a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
48348a978a17SVictor Perevertkin BOOLEAN
48358a978a17SVictor Perevertkin FxIoQueue::ProcessCancelledRequests(
48368a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
48378a978a17SVictor Perevertkin     )
48388a978a17SVictor Perevertkin /*++
48398a978a17SVictor Perevertkin 
48408a978a17SVictor Perevertkin     Routine Description:
48418a978a17SVictor Perevertkin 
48428a978a17SVictor Perevertkin     Process any cancelled requests
48438a978a17SVictor Perevertkin     Called with the Queue lock held
48448a978a17SVictor Perevertkin     Can drop and re-acquire the queue lock
48458a978a17SVictor Perevertkin     Returns with the Queue lock held
48468a978a17SVictor Perevertkin 
48478a978a17SVictor Perevertkin     Arguments:
48488a978a17SVictor Perevertkin 
48498a978a17SVictor Perevertkin     Return Value:
48508a978a17SVictor Perevertkin     None
48518a978a17SVictor Perevertkin 
48528a978a17SVictor Perevertkin   --*/
48538a978a17SVictor Perevertkin {
48548a978a17SVictor Perevertkin     PLIST_ENTRY   pEntry;
48558a978a17SVictor Perevertkin     FxRequest*  pRequest;
48568a978a17SVictor Perevertkin 
48578a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
48588a978a17SVictor Perevertkin 
48598a978a17SVictor Perevertkin     if (IsPowerStateNotifyingDriver()) {
48608a978a17SVictor Perevertkin         //
48618a978a17SVictor Perevertkin         // We will not process cancelled request while the driver is being
48628a978a17SVictor Perevertkin         // notified to stop processing request to avoid double completion
48638a978a17SVictor Perevertkin         // of the request.
48648a978a17SVictor Perevertkin         //
48658a978a17SVictor Perevertkin         return FALSE;
48668a978a17SVictor Perevertkin     }
48678a978a17SVictor Perevertkin 
48688a978a17SVictor Perevertkin     while (!IsListEmpty(&m_Cancelled)) {
48698a978a17SVictor Perevertkin         pEntry = m_Cancelled.Flink;
48708a978a17SVictor Perevertkin 
48718a978a17SVictor Perevertkin         RemoveEntryList(pEntry);
48728a978a17SVictor Perevertkin 
48738a978a17SVictor Perevertkin         // FxRequest ensures its not on any list on checked builds
48748a978a17SVictor Perevertkin         InitializeListHead(pEntry);
48758a978a17SVictor Perevertkin 
48768a978a17SVictor Perevertkin         pRequest = FxRequest::_FromOwnerListEntry(FxListEntryQueueOwned, pEntry);
48778a978a17SVictor Perevertkin 
48788a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO,
48798a978a17SVictor Perevertkin                             "Calling CancelRoutine routine "
48808a978a17SVictor Perevertkin                             "for WDFREQUEST 0x%p on WDFQUEUE 0x%p",
48818a978a17SVictor Perevertkin                             pRequest->GetHandle(), GetObjectHandle());
48828a978a17SVictor Perevertkin 
48838a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
48848a978a17SVictor Perevertkin 
48858a978a17SVictor Perevertkin             // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
48868a978a17SVictor Perevertkin             pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED);
48878a978a17SVictor Perevertkin         }
48888a978a17SVictor Perevertkin 
48898a978a17SVictor Perevertkin         Unlock(*PreviousIrql);
48908a978a17SVictor Perevertkin 
48918a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
48928a978a17SVictor Perevertkin             ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
48938a978a17SVictor Perevertkin         }
48948a978a17SVictor Perevertkin 
48958a978a17SVictor Perevertkin         //
48968a978a17SVictor Perevertkin         // Notify the driver of cancel desire
48978a978a17SVictor Perevertkin         //
48988a978a17SVictor Perevertkin         pRequest->m_CancelRoutine.InvokeCancel(
48998a978a17SVictor Perevertkin             m_IoCancelCallbackLockPtr,
49008a978a17SVictor Perevertkin             pRequest->GetHandle()
49018a978a17SVictor Perevertkin             );
49028a978a17SVictor Perevertkin 
49038a978a17SVictor Perevertkin         //
49048a978a17SVictor Perevertkin         // Release the reference that FxRequest took out on itself
49058a978a17SVictor Perevertkin         // when it was placed onto the FxIrpQueue. It is now leaving
49068a978a17SVictor Perevertkin         // the FxIrpQueue due to cancel, and we own this final
49078a978a17SVictor Perevertkin         // release.
49088a978a17SVictor Perevertkin         //
49098a978a17SVictor Perevertkin         pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
49108a978a17SVictor Perevertkin 
49118a978a17SVictor Perevertkin         Lock(PreviousIrql);
49128a978a17SVictor Perevertkin     }
49138a978a17SVictor Perevertkin 
49148a978a17SVictor Perevertkin     return TRUE;
49158a978a17SVictor Perevertkin }
49168a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)49178a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
49188a978a17SVictor Perevertkin BOOLEAN
49198a978a17SVictor Perevertkin FxIoQueue::ProcessCancelledRequestsOnQueue(
49208a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
49218a978a17SVictor Perevertkin     )
49228a978a17SVictor Perevertkin /*++
49238a978a17SVictor Perevertkin 
49248a978a17SVictor Perevertkin     Routine Description:
49258a978a17SVictor Perevertkin 
49268a978a17SVictor Perevertkin     Process any cancelled requests
49278a978a17SVictor Perevertkin     Called with the Queue lock held
49288a978a17SVictor Perevertkin     Can drop and re-acquire the queue lock
49298a978a17SVictor Perevertkin     Returns with the Queue lock held
49308a978a17SVictor Perevertkin 
49318a978a17SVictor Perevertkin     Arguments:
49328a978a17SVictor Perevertkin 
49338a978a17SVictor Perevertkin     Return Value:
49348a978a17SVictor Perevertkin     None
49358a978a17SVictor Perevertkin 
49368a978a17SVictor Perevertkin   --*/
49378a978a17SVictor Perevertkin {
49388a978a17SVictor Perevertkin     PLIST_ENTRY   pEntry;
49398a978a17SVictor Perevertkin     FxRequest*  pRequest;
49408a978a17SVictor Perevertkin 
49418a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
49428a978a17SVictor Perevertkin 
49438a978a17SVictor Perevertkin     if (IsPowerStateNotifyingDriver()) {
49448a978a17SVictor Perevertkin         //
49458a978a17SVictor Perevertkin         // We will not process cancelled request while the driver is being
49468a978a17SVictor Perevertkin         // notified to stop/resume processing request to avoid double
49478a978a17SVictor Perevertkin         // completion of the request.
49488a978a17SVictor Perevertkin         //
49498a978a17SVictor Perevertkin         return FALSE;
49508a978a17SVictor Perevertkin     }
49518a978a17SVictor Perevertkin 
49528a978a17SVictor Perevertkin     while (!IsListEmpty(&m_CanceledOnQueueList)) {
49538a978a17SVictor Perevertkin         pEntry = m_CanceledOnQueueList.Flink;
49548a978a17SVictor Perevertkin 
49558a978a17SVictor Perevertkin         RemoveEntryList(pEntry);
49568a978a17SVictor Perevertkin 
49578a978a17SVictor Perevertkin         // FxRequest ensures its not on any list on checked builds
49588a978a17SVictor Perevertkin         InitializeListHead(pEntry);
49598a978a17SVictor Perevertkin 
49608a978a17SVictor Perevertkin         pRequest = FxRequest::_FromOwnerListEntry(FxListEntryQueueOwned, pEntry);
49618a978a17SVictor Perevertkin 
49628a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO,
49638a978a17SVictor Perevertkin                             "Calling CanceledOnQueue routine "
49648a978a17SVictor Perevertkin                             "for WDFREQUEST 0x%p on WDFQUEUE 0x%p",
49658a978a17SVictor Perevertkin                             pRequest->GetHandle(), GetObjectHandle());
49668a978a17SVictor Perevertkin 
49678a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
49688a978a17SVictor Perevertkin 
49698a978a17SVictor Perevertkin             // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
49708a978a17SVictor Perevertkin             pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED);
49718a978a17SVictor Perevertkin         }
49728a978a17SVictor Perevertkin 
49738a978a17SVictor Perevertkin         Unlock(*PreviousIrql);
49748a978a17SVictor Perevertkin 
49758a978a17SVictor Perevertkin         if (FxDriverGlobals->FxVerifierOn) {
49768a978a17SVictor Perevertkin             ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
49778a978a17SVictor Perevertkin         }
49788a978a17SVictor Perevertkin 
49798a978a17SVictor Perevertkin         //
49808a978a17SVictor Perevertkin         // Notify the driver
49818a978a17SVictor Perevertkin         //
49828a978a17SVictor Perevertkin         m_IoCanceledOnQueue.Invoke(GetHandle(), pRequest->GetHandle());
49838a978a17SVictor Perevertkin 
49848a978a17SVictor Perevertkin         Lock(PreviousIrql);
49858a978a17SVictor Perevertkin     }
49868a978a17SVictor Perevertkin 
49878a978a17SVictor Perevertkin     return TRUE;
49888a978a17SVictor Perevertkin }
49898a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)49908a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
49918a978a17SVictor Perevertkin BOOLEAN
49928a978a17SVictor Perevertkin FxIoQueue::ProcessPowerEvents(
49938a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
49948a978a17SVictor Perevertkin     )
49958a978a17SVictor Perevertkin /*++
49968a978a17SVictor Perevertkin 
49978a978a17SVictor Perevertkin Routine Description:
49988a978a17SVictor Perevertkin 
49998a978a17SVictor Perevertkin     Processes the power state machine for I/O queues.
50008a978a17SVictor Perevertkin 
50018a978a17SVictor Perevertkin     Called with Queue lock held, but can drop and re-acquire
50028a978a17SVictor Perevertkin     it when it has to deliver event callbacks to the device driver.
50038a978a17SVictor Perevertkin 
50048a978a17SVictor Perevertkin     This can modify queue state as it transits the state machine, and
50058a978a17SVictor Perevertkin     is called from the main event processing loop DispatchEvents().
50068a978a17SVictor Perevertkin 
50078a978a17SVictor Perevertkin     Handling "in-flight" I/O requests in the device driver due
50088a978a17SVictor Perevertkin     to a power state transition (stopping) is tricky, and
50098a978a17SVictor Perevertkin     involves a complex state machine.
50108a978a17SVictor Perevertkin 
50118a978a17SVictor Perevertkin     The device driver must ensure that all in-flight I/O is stopped
50128a978a17SVictor Perevertkin     before it can release the thread calling into the driver to
50138a978a17SVictor Perevertkin     perform the power state transition, otherwise a system crash
50148a978a17SVictor Perevertkin     can result from accessing hardware after resources have been removed.
50158a978a17SVictor Perevertkin 
50168a978a17SVictor Perevertkin     In WDF, this burden is placed on FxIoQueue, so that the device driver
50178a978a17SVictor Perevertkin     does not have to implement the more complex aspects of this code,
50188a978a17SVictor Perevertkin     but can rely on notifications from the queue serialized under the
50198a978a17SVictor Perevertkin     IRQL level and locking it has configured.
50208a978a17SVictor Perevertkin 
50218a978a17SVictor Perevertkin 
50228a978a17SVictor Perevertkin     Implementation of FxIoQueue Power state machine:
50238a978a17SVictor Perevertkin     ------------------------------------------
50248a978a17SVictor Perevertkin 
50258a978a17SVictor Perevertkin     Since we must drop our lock to callback into the device
50268a978a17SVictor Perevertkin     driver for power notifications, the processing must occur
50278a978a17SVictor Perevertkin     as a state machine with three lists.
50288a978a17SVictor Perevertkin 
50298a978a17SVictor Perevertkin     On entry to the power stop state, any "in-flight" I/O requests
50308a978a17SVictor Perevertkin     are recorded on the m_DriverOwned list using
50318a978a17SVictor Perevertkin     FxRequest::FxListEntryDriverOwned for linkage.
50328a978a17SVictor Perevertkin 
50338a978a17SVictor Perevertkin     All of the requests on m_DriverOwned are moved to m_PowerNotify
50348a978a17SVictor Perevertkin     while holding the lock, with m_DriverOwned cleared. The state is changed
50358a978a17SVictor Perevertkin     to indicate that the driver is now being notified of requests.
50368a978a17SVictor Perevertkin 
50378a978a17SVictor Perevertkin     While in the driver notification state, requests are taken from the
50388a978a17SVictor Perevertkin     m_PowerNotify list, and moved on to the m_PowerDriverNotified list while
50398a978a17SVictor Perevertkin     under the lock, and the request is notified to the device driver
50408a978a17SVictor Perevertkin     by the callback while dropping the lock and re-acquiring the lock.
50418a978a17SVictor Perevertkin 
50428a978a17SVictor Perevertkin     As the driver acknowledges the power notification, it calls
50438a978a17SVictor Perevertkin     WdfRequestStopAcknowledge (FxIoQueue::StopAcknowledge) which moves the
50448a978a17SVictor Perevertkin     request from the m_PowerDriverNotified list back to the m_DriverOwned
50458a978a17SVictor Perevertkin     list.
50468a978a17SVictor Perevertkin 
50478a978a17SVictor Perevertkin     The device driver could also complete requests, in which case they
50488a978a17SVictor Perevertkin     just dis-appear from the lists by the completion code doing
50498a978a17SVictor Perevertkin     a RemoveEntryList on FxRequest::FxListEntryDriverOwned.
50508a978a17SVictor Perevertkin 
50518a978a17SVictor Perevertkin     This occurs until the m_PowerNotify list is empty, in which case
50528a978a17SVictor Perevertkin     the state is changed to driver notified.
50538a978a17SVictor Perevertkin 
50548a978a17SVictor Perevertkin     While in the driver notified state, the queue event processing continues
50558a978a17SVictor Perevertkin     until the m_PowerDriverNotified list is empty, and when it is, the
50568a978a17SVictor Perevertkin     stopped state is set, and the event m_PowerIdle is set. This releases
50578a978a17SVictor Perevertkin     the thread waiting on the power state transition in which all of the
50588a978a17SVictor Perevertkin     device drivers "in-flight" I/O has been stopped and accounted for.
50598a978a17SVictor Perevertkin 
50608a978a17SVictor Perevertkin     State Transitions:
50618a978a17SVictor Perevertkin     --------------
50628a978a17SVictor Perevertkin 
50638a978a17SVictor Perevertkin     During Stop:
50648a978a17SVictor Perevertkin 
50658a978a17SVictor Perevertkin     FxIoQueuePowerOn
50668a978a17SVictor Perevertkin         --> FxIoQueuePowerStartingTransition
50678a978a17SVictor Perevertkin             --> FxIoQueuePowerStopping
50688a978a17SVictor Perevertkin                 --> FxIoQueuePowerStoppingNotifyingDriver
50698a978a17SVictor Perevertkin                     --> FxIoQueuePowerStoppingDriverNotified
50708a978a17SVictor Perevertkin                         --> FxIoQueuePowerOff
50718a978a17SVictor Perevertkin 
50728a978a17SVictor Perevertkin     During Purge:
50738a978a17SVictor Perevertkin 
50748a978a17SVictor Perevertkin     FxIoQueuePowerPurge
50758a978a17SVictor Perevertkin         --> FxIoQueuePowerPurgeNotifyingDriver
50768a978a17SVictor Perevertkin             --> FxIoQueuePowerPurgeDriverNotified
50778a978a17SVictor Perevertkin                 --> FxIoQueuePowerOff
50788a978a17SVictor Perevertkin 
50798a978a17SVictor Perevertkin 
50808a978a17SVictor Perevertkin     During Resume:
50818a978a17SVictor Perevertkin 
50828a978a17SVictor Perevertkin     FxIoQueuePowerOff
50838a978a17SVictor Perevertkin         --> FxIoQueuePowerRestarting
50848a978a17SVictor Perevertkin             --> FxIoQueuePowerRestartingNotifyingDriver
50858a978a17SVictor Perevertkin                 --> FxIoQueuePowerRestartingDriverNotified
50868a978a17SVictor Perevertkin                     --> FxIoQueuePowerOn
50878a978a17SVictor Perevertkin 
50888a978a17SVictor Perevertkin Arguments:
50898a978a17SVictor Perevertkin 
50908a978a17SVictor Perevertkin Return Value:
50918a978a17SVictor Perevertkin 
50928a978a17SVictor Perevertkin     TRUE - Continue processing the event loop
50938a978a17SVictor Perevertkin     FALSE - Stop processing event loop
50948a978a17SVictor Perevertkin 
50958a978a17SVictor Perevertkin --*/
50968a978a17SVictor Perevertkin {
50978a978a17SVictor Perevertkin     PLIST_ENTRY   Entry;
50988a978a17SVictor Perevertkin     FxRequest*    pRequest;
50998a978a17SVictor Perevertkin 
51008a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
51018a978a17SVictor Perevertkin 
51028a978a17SVictor Perevertkin     switch(m_PowerState) {
51038a978a17SVictor Perevertkin 
51048a978a17SVictor Perevertkin     case FxIoQueuePowerStartingTransition:
51058a978a17SVictor Perevertkin         if (m_Dispatching == 1) {
51068a978a17SVictor Perevertkin 
51078a978a17SVictor Perevertkin             //
51088a978a17SVictor Perevertkin             // If we are the last routine actively dispatching callbacks to
51098a978a17SVictor Perevertkin             // the device driver under a Power stop, then we must set the
51108a978a17SVictor Perevertkin             // event specifying no more callbacks are active.
51118a978a17SVictor Perevertkin             //
51128a978a17SVictor Perevertkin             m_PowerIdle.Set();
51138a978a17SVictor Perevertkin         }
51148a978a17SVictor Perevertkin 
51158a978a17SVictor Perevertkin         return FALSE;
51168a978a17SVictor Perevertkin 
51178a978a17SVictor Perevertkin     case FxIoQueuePowerStopping:
51188a978a17SVictor Perevertkin         //
51198a978a17SVictor Perevertkin         // Set state to FxIoQueuePowerPurgeNotifyingDriver
51208a978a17SVictor Perevertkin         //
51218a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerStoppingNotifyingDriver;
51228a978a17SVictor Perevertkin 
51238a978a17SVictor Perevertkin         // This should be empty on entry to this state
51248a978a17SVictor Perevertkin         ASSERT(IsListEmpty(&this->m_PowerNotify));
51258a978a17SVictor Perevertkin 
51268a978a17SVictor Perevertkin         if (!IsListEmpty(&m_DriverOwned)) {
51278a978a17SVictor Perevertkin 
51288a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
51298a978a17SVictor Perevertkin                                 "Power Stop: WDFQUEUE 0x%p is powering off "
51308a978a17SVictor Perevertkin                                 "with in-flight requests",
51318a978a17SVictor Perevertkin                                 GetObjectHandle());
51328a978a17SVictor Perevertkin 
51338a978a17SVictor Perevertkin 
51348a978a17SVictor Perevertkin             // Ensure the logic of m_DriverOwned is correct
51358a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned);
51368a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned);
51378a978a17SVictor Perevertkin 
51388a978a17SVictor Perevertkin             //
51398a978a17SVictor Perevertkin             // Move all requests on m_DriverOwned to m_PowerNotify
51408a978a17SVictor Perevertkin             //
51418a978a17SVictor Perevertkin             m_PowerNotify.Flink = m_DriverOwned.Flink;
51428a978a17SVictor Perevertkin             m_PowerNotify.Blink = m_DriverOwned.Blink;
51438a978a17SVictor Perevertkin             m_PowerNotify.Flink->Blink = &m_PowerNotify;
51448a978a17SVictor Perevertkin             m_PowerNotify.Blink->Flink = &m_PowerNotify;
51458a978a17SVictor Perevertkin 
51468a978a17SVictor Perevertkin             // This is now empty
51478a978a17SVictor Perevertkin             InitializeListHead(&m_DriverOwned);
51488a978a17SVictor Perevertkin         }
51498a978a17SVictor Perevertkin         else {
51508a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
51518a978a17SVictor Perevertkin                                 "Power Stop: WDFQUEUE 0x%p is powering off without "
51528a978a17SVictor Perevertkin                                 "in-flight requests",GetObjectHandle());
51538a978a17SVictor Perevertkin         }
51548a978a17SVictor Perevertkin 
51558a978a17SVictor Perevertkin         //
51568a978a17SVictor Perevertkin         // Return to main processing loop which will callback to
51578a978a17SVictor Perevertkin         // process notifications
51588a978a17SVictor Perevertkin         //
51598a978a17SVictor Perevertkin         return TRUE;
51608a978a17SVictor Perevertkin 
51618a978a17SVictor Perevertkin     case FxIoQueuePowerPurge:
51628a978a17SVictor Perevertkin         //
51638a978a17SVictor Perevertkin         // Set state to FxIoQueuePowerPurgeNotifyingDriver
51648a978a17SVictor Perevertkin         //
51658a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerPurgeNotifyingDriver;
51668a978a17SVictor Perevertkin 
51678a978a17SVictor Perevertkin         // This should be empty on entry to this state
51688a978a17SVictor Perevertkin         ASSERT(IsListEmpty(&this->m_PowerNotify));
51698a978a17SVictor Perevertkin 
51708a978a17SVictor Perevertkin         if (!IsListEmpty(&m_DriverOwned)) {
51718a978a17SVictor Perevertkin 
51728a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
51738a978a17SVictor Perevertkin                                 "Power Stop: WDFQUEUE 0x%p is purging with "
51748a978a17SVictor Perevertkin                                 "in-flight requests",GetObjectHandle());
51758a978a17SVictor Perevertkin 
51768a978a17SVictor Perevertkin             // Ensure the logic of m_DriverOwned is correct
51778a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned);
51788a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned);
51798a978a17SVictor Perevertkin 
51808a978a17SVictor Perevertkin             //
51818a978a17SVictor Perevertkin             // Move all requests on m_DriverOwned to m_PowerNotify
51828a978a17SVictor Perevertkin             //
51838a978a17SVictor Perevertkin             m_PowerNotify.Flink = m_DriverOwned.Flink;
51848a978a17SVictor Perevertkin             m_PowerNotify.Blink = m_DriverOwned.Blink;
51858a978a17SVictor Perevertkin             m_PowerNotify.Flink->Blink = &m_PowerNotify;
51868a978a17SVictor Perevertkin             m_PowerNotify.Blink->Flink = &m_PowerNotify;
51878a978a17SVictor Perevertkin 
51888a978a17SVictor Perevertkin             // This is now empty
51898a978a17SVictor Perevertkin             InitializeListHead(&m_DriverOwned);
51908a978a17SVictor Perevertkin         }
51918a978a17SVictor Perevertkin         else {
51928a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
51938a978a17SVictor Perevertkin                                 "Power purge: WDFQUEUE 0x%p is purging without "
51948a978a17SVictor Perevertkin                                 "in-flight requests", GetObjectHandle());
51958a978a17SVictor Perevertkin         }
51968a978a17SVictor Perevertkin 
51978a978a17SVictor Perevertkin         //
51988a978a17SVictor Perevertkin         // Return to main processing loop which will callback to
51998a978a17SVictor Perevertkin         // process notifications
52008a978a17SVictor Perevertkin         //
52018a978a17SVictor Perevertkin         return TRUE;
52028a978a17SVictor Perevertkin 
52038a978a17SVictor Perevertkin     case FxIoQueuePowerStoppingNotifyingDriver:  {
52048a978a17SVictor Perevertkin 
52058a978a17SVictor Perevertkin         FxIoQueueIoStop   stopCallback;
52068a978a17SVictor Perevertkin 
52078a978a17SVictor Perevertkin         //
52088a978a17SVictor Perevertkin         // If the list of requests to notify the driver about is
52098a978a17SVictor Perevertkin         // empty, change to the notified state.
52108a978a17SVictor Perevertkin         //
52118a978a17SVictor Perevertkin         if (IsListEmpty(&m_PowerNotify)) {
52128a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerStoppingDriverNotified;
52138a978a17SVictor Perevertkin 
52148a978a17SVictor Perevertkin             //
52158a978a17SVictor Perevertkin             // Return to main processing loop which will callback to
52168a978a17SVictor Perevertkin             // process the wait/signaling for the driver to acknowledge
52178a978a17SVictor Perevertkin             // all stops.
52188a978a17SVictor Perevertkin             //
52198a978a17SVictor Perevertkin             return TRUE;
52208a978a17SVictor Perevertkin         }
52218a978a17SVictor Perevertkin 
52228a978a17SVictor Perevertkin         //
52238a978a17SVictor Perevertkin         // Notify each entry in m_PowerNotify into the driver
52248a978a17SVictor Perevertkin         //
52258a978a17SVictor Perevertkin 
52268a978a17SVictor Perevertkin         // Remove from the notify list, place it on the driver notified list
52278a978a17SVictor Perevertkin         Entry = RemoveHeadList(&m_PowerNotify);
52288a978a17SVictor Perevertkin 
52298a978a17SVictor Perevertkin         InsertTailList(&m_PowerDriverNotified, Entry);
52308a978a17SVictor Perevertkin 
52318a978a17SVictor Perevertkin         // Retrieve the FxRequest
52328a978a17SVictor Perevertkin         pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry);
52338a978a17SVictor Perevertkin 
52348a978a17SVictor Perevertkin         stopCallback = m_IoStop;
52358a978a17SVictor Perevertkin 
52368a978a17SVictor Perevertkin         //
52378a978a17SVictor Perevertkin         // Notify driver by callback.
52388a978a17SVictor Perevertkin         //
52398a978a17SVictor Perevertkin         // If no callback is registered, the power thread will in effect
52408a978a17SVictor Perevertkin         // wait until the driver completes or cancels all requests.
52418a978a17SVictor Perevertkin         //
52428a978a17SVictor Perevertkin         if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) {
52438a978a17SVictor Perevertkin             ULONG ActionFlags = WdfRequestStopActionSuspend;
52448a978a17SVictor Perevertkin 
52458a978a17SVictor Perevertkin             if(pRequest->IsInIrpQueue(&m_DriverCancelable)) {
52468a978a17SVictor Perevertkin                 ActionFlags |= WdfRequestStopRequestCancelable;
52478a978a17SVictor Perevertkin             }
52488a978a17SVictor Perevertkin 
52498a978a17SVictor Perevertkin             DoTraceLevelMessage(
52508a978a17SVictor Perevertkin                 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
52518a978a17SVictor Perevertkin                 "Power Stop Notifying Driver, WDFQUEUE 0x%p, WDFREQUEST 0x%p",
52528a978a17SVictor Perevertkin                 GetObjectHandle(), pRequest->GetObjectHandle());
52538a978a17SVictor Perevertkin 
52548a978a17SVictor Perevertkin             // Driver could be calling RequestComplete as we attempt to stop
52558a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_HOLD_TAG);
52568a978a17SVictor Perevertkin 
52578a978a17SVictor Perevertkin             Unlock(*PreviousIrql);
52588a978a17SVictor Perevertkin 
52598a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
52608a978a17SVictor Perevertkin                 pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT);
52618a978a17SVictor Perevertkin             }
52628a978a17SVictor Perevertkin 
52638a978a17SVictor Perevertkin             stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags);
52648a978a17SVictor Perevertkin 
52658a978a17SVictor Perevertkin             pRequest->RELEASE(FXREQUEST_HOLD_TAG);
52668a978a17SVictor Perevertkin 
52678a978a17SVictor Perevertkin             Lock(PreviousIrql);
52688a978a17SVictor Perevertkin         }
52698a978a17SVictor Perevertkin 
52708a978a17SVictor Perevertkin         //
52718a978a17SVictor Perevertkin         // As they are acknowledged, they will move back to m_DriverOwned.
52728a978a17SVictor Perevertkin         //
52738a978a17SVictor Perevertkin         // If the driver completes them, they go away.
52748a978a17SVictor Perevertkin         //
52758a978a17SVictor Perevertkin 
52768a978a17SVictor Perevertkin         // Return to main processing loop and continue processing notifications
52778a978a17SVictor Perevertkin         return TRUE;
52788a978a17SVictor Perevertkin     }
52798a978a17SVictor Perevertkin 
52808a978a17SVictor Perevertkin     case FxIoQueuePowerPurgeNotifyingDriver: {
52818a978a17SVictor Perevertkin 
52828a978a17SVictor Perevertkin         FxIoQueueIoStop   stopCallback;
52838a978a17SVictor Perevertkin 
52848a978a17SVictor Perevertkin         //
52858a978a17SVictor Perevertkin         // If the list of requests to notify the driver about is
52868a978a17SVictor Perevertkin         // empty, change to the notified state.
52878a978a17SVictor Perevertkin         //
52888a978a17SVictor Perevertkin         if (IsListEmpty(&m_PowerNotify)) {
52898a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerPurgeDriverNotified;
52908a978a17SVictor Perevertkin 
52918a978a17SVictor Perevertkin             //
52928a978a17SVictor Perevertkin             // Return to main processing loop which will callback to
52938a978a17SVictor Perevertkin             // process the wait/signaling for the driver to acknowledge
52948a978a17SVictor Perevertkin             // all stops.
52958a978a17SVictor Perevertkin             //
52968a978a17SVictor Perevertkin             return TRUE;
52978a978a17SVictor Perevertkin         }
52988a978a17SVictor Perevertkin 
52998a978a17SVictor Perevertkin         //
53008a978a17SVictor Perevertkin         // Notify each entry in m_PowerNotify into the driver
53018a978a17SVictor Perevertkin         //
53028a978a17SVictor Perevertkin 
53038a978a17SVictor Perevertkin         // Remove from the notify list, place it on the driver notified list
53048a978a17SVictor Perevertkin         Entry = RemoveHeadList(&m_PowerNotify);
53058a978a17SVictor Perevertkin 
53068a978a17SVictor Perevertkin         InsertTailList(&m_PowerDriverNotified, Entry);
53078a978a17SVictor Perevertkin 
53088a978a17SVictor Perevertkin         // Retrieve the FxRequest
53098a978a17SVictor Perevertkin         pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry);
53108a978a17SVictor Perevertkin 
53118a978a17SVictor Perevertkin         stopCallback = m_IoStop;
53128a978a17SVictor Perevertkin 
53138a978a17SVictor Perevertkin         //
53148a978a17SVictor Perevertkin         // Make sure power stop state is cleared before invoking the stop callback.
53158a978a17SVictor Perevertkin         //
53168a978a17SVictor Perevertkin         pRequest->ClearPowerStopState();
53178a978a17SVictor Perevertkin 
53188a978a17SVictor Perevertkin         //
53198a978a17SVictor Perevertkin         // Notify driver by callback.
53208a978a17SVictor Perevertkin         //
53218a978a17SVictor Perevertkin         // If no callback is registered, the power thread will in effect
53228a978a17SVictor Perevertkin         // wait until the driver completes or cancels all requests.
53238a978a17SVictor Perevertkin         //
53248a978a17SVictor Perevertkin         if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) {
53258a978a17SVictor Perevertkin             ULONG ActionFlags = WdfRequestStopActionPurge;
53268a978a17SVictor Perevertkin 
53278a978a17SVictor Perevertkin             if(pRequest->IsInIrpQueue(&m_DriverCancelable)) {
53288a978a17SVictor Perevertkin                 ActionFlags |= WdfRequestStopRequestCancelable;
53298a978a17SVictor Perevertkin             }
53308a978a17SVictor Perevertkin 
53318a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
53328a978a17SVictor Perevertkin                                 "Power Purge Notifying Driver "
53338a978a17SVictor Perevertkin                                 "WDFQUEUE 0x%p, WDFREQUEST 0x%p",
53348a978a17SVictor Perevertkin                                 GetObjectHandle(),pRequest->GetHandle());
53358a978a17SVictor Perevertkin 
53368a978a17SVictor Perevertkin             // Driver could be calling RequestComplete as we attempt to stop
53378a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_HOLD_TAG);
53388a978a17SVictor Perevertkin 
53398a978a17SVictor Perevertkin             Unlock(*PreviousIrql);
53408a978a17SVictor Perevertkin 
53418a978a17SVictor Perevertkin             if (FxDriverGlobals->FxVerifierOn) {
53428a978a17SVictor Perevertkin                 pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT);
53438a978a17SVictor Perevertkin             }
53448a978a17SVictor Perevertkin 
53458a978a17SVictor Perevertkin             stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags);
53468a978a17SVictor Perevertkin 
53478a978a17SVictor Perevertkin             pRequest->RELEASE(FXREQUEST_HOLD_TAG);
53488a978a17SVictor Perevertkin 
53498a978a17SVictor Perevertkin             Lock(PreviousIrql);
53508a978a17SVictor Perevertkin         }
53518a978a17SVictor Perevertkin 
53528a978a17SVictor Perevertkin         //
53538a978a17SVictor Perevertkin         // As they are acknowledged, they will move back to m_DriverOwned.
53548a978a17SVictor Perevertkin         //
53558a978a17SVictor Perevertkin         // If the driver completes them, they go away.
53568a978a17SVictor Perevertkin         //
53578a978a17SVictor Perevertkin 
53588a978a17SVictor Perevertkin         // Return to main processing loop and continue processing notifications
53598a978a17SVictor Perevertkin         return TRUE;
53608a978a17SVictor Perevertkin     }
53618a978a17SVictor Perevertkin 
53628a978a17SVictor Perevertkin     case FxIoQueuePowerStoppingDriverNotified:
53638a978a17SVictor Perevertkin     case FxIoQueuePowerPurgeDriverNotified: {
53648a978a17SVictor Perevertkin 
53658a978a17SVictor Perevertkin         PLIST_ENTRY thisEntry, nextEntry, listHead;
53668a978a17SVictor Perevertkin         LIST_ENTRY acknowledgedList;
53678a978a17SVictor Perevertkin         BOOLEAN continueProcessing = FALSE;
53688a978a17SVictor Perevertkin 
53698a978a17SVictor Perevertkin         InitializeListHead(&acknowledgedList);
53708a978a17SVictor Perevertkin 
53718a978a17SVictor Perevertkin         //
53728a978a17SVictor Perevertkin         // First move all the acknowledged requests to local list and then
53738a978a17SVictor Perevertkin         // process the local list. We have do that in two steps because
53748a978a17SVictor Perevertkin         // ProcessAcknowledgedRequests drops and reacquires the lock.
53758a978a17SVictor Perevertkin         //
53768a978a17SVictor Perevertkin         listHead = &m_PowerDriverNotified;
53778a978a17SVictor Perevertkin 
53788a978a17SVictor Perevertkin         for (thisEntry = listHead->Flink;
53798a978a17SVictor Perevertkin              thisEntry != listHead;
53808a978a17SVictor Perevertkin              thisEntry = nextEntry) {
53818a978a17SVictor Perevertkin 
53828a978a17SVictor Perevertkin             // Retrieve the FxRequest
53838a978a17SVictor Perevertkin             pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, thisEntry);
53848a978a17SVictor Perevertkin 
53858a978a17SVictor Perevertkin             nextEntry = thisEntry->Flink;
53868a978a17SVictor Perevertkin 
53878a978a17SVictor Perevertkin             if (pRequest->IsPowerStopAcknowledged()) {
53888a978a17SVictor Perevertkin                 RemoveEntryList(thisEntry);
53898a978a17SVictor Perevertkin                 InsertTailList(&acknowledgedList, thisEntry);
53908a978a17SVictor Perevertkin             }
53918a978a17SVictor Perevertkin         }
53928a978a17SVictor Perevertkin 
53938a978a17SVictor Perevertkin         //
53948a978a17SVictor Perevertkin         // Process all the acknowledged request from the local list.
53958a978a17SVictor Perevertkin         //
53968a978a17SVictor Perevertkin         while (!IsListEmpty(&acknowledgedList))
53978a978a17SVictor Perevertkin         {
53988a978a17SVictor Perevertkin             thisEntry = RemoveHeadList(&acknowledgedList);
53998a978a17SVictor Perevertkin             pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, thisEntry);
54008a978a17SVictor Perevertkin             ProcessAcknowledgedRequests(pRequest, PreviousIrql);
54018a978a17SVictor Perevertkin 
54028a978a17SVictor Perevertkin             //
54038a978a17SVictor Perevertkin             // When this function drops the lock, other threads may attempt
54048a978a17SVictor Perevertkin             // to dispatch but fail since we are currently dispatching.
54058a978a17SVictor Perevertkin             // We need to be sure to process any pending events that other
54068a978a17SVictor Perevertkin             // threads initiated but could not be dispatch.  The acknowledged
54078a978a17SVictor Perevertkin             // list will eventually be cleared out, allowing exit paths from
54088a978a17SVictor Perevertkin             // this function to return control to the driver.
54098a978a17SVictor Perevertkin             //
54108a978a17SVictor Perevertkin             continueProcessing = TRUE;
54118a978a17SVictor Perevertkin         }
54128a978a17SVictor Perevertkin 
54138a978a17SVictor Perevertkin         //
54148a978a17SVictor Perevertkin         // Check to see if there are any unacknowledged requests.
54158a978a17SVictor Perevertkin         //
54168a978a17SVictor Perevertkin         if (!IsListEmpty(&m_PowerDriverNotified)) {
54178a978a17SVictor Perevertkin 
54188a978a17SVictor Perevertkin             //
54198a978a17SVictor Perevertkin             // If there are still entries on the list, we potentially return
54208a978a17SVictor Perevertkin             // FALSE to tell the main event dispatching loop to return to
54218a978a17SVictor Perevertkin             // the device driver, since we are awaiting response from
54228a978a17SVictor Perevertkin             // the driver while in this state.
54238a978a17SVictor Perevertkin             //
54248a978a17SVictor Perevertkin 
54258a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
54268a978a17SVictor Perevertkin                                 "Power Stop: Waiting for Driver to complete or "
54278a978a17SVictor Perevertkin                                 "acknowledge in-flight requests on WDFQUEUE 0x%p",
54288a978a17SVictor Perevertkin                                 GetObjectHandle());
54298a978a17SVictor Perevertkin 
54308a978a17SVictor Perevertkin             return continueProcessing;
54318a978a17SVictor Perevertkin         }
54328a978a17SVictor Perevertkin 
54338a978a17SVictor Perevertkin         //
54348a978a17SVictor Perevertkin         // Check to see if there are any requests in the middle of two-phase-completion.
54358a978a17SVictor Perevertkin         // If so, bail out and wait.
54368a978a17SVictor Perevertkin         //
54378a978a17SVictor Perevertkin         if (m_TwoPhaseCompletions != 0) {
54388a978a17SVictor Perevertkin 
54398a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
54408a978a17SVictor Perevertkin                                 "Power Stop: Waiting for Driver to complete or "
54418a978a17SVictor Perevertkin                                 "acknowledge in-flight requests on WDFQUEUE 0x%p",
54428a978a17SVictor Perevertkin                                 GetObjectHandle());
54438a978a17SVictor Perevertkin 
54448a978a17SVictor Perevertkin             return continueProcessing;
54458a978a17SVictor Perevertkin         }
54468a978a17SVictor Perevertkin 
54478a978a17SVictor Perevertkin         //
54488a978a17SVictor Perevertkin         // All the requests are acknowledged. We will signal the pnp thread waiting
54498a978a17SVictor Perevertkin         // in StopProcessingForPower to continue if we are the last one to visit
54508a978a17SVictor Perevertkin         // the dispatch event loop.
54518a978a17SVictor Perevertkin         //
54528a978a17SVictor Perevertkin         //
54538a978a17SVictor Perevertkin         if ( m_Dispatching == 1) {
54548a978a17SVictor Perevertkin 
54558a978a17SVictor Perevertkin             //
54568a978a17SVictor Perevertkin             // If we are the last routine actively dispatching callbacks to
54578a978a17SVictor Perevertkin             // the device driver under a Power stop, then we must set the
54588a978a17SVictor Perevertkin             // event specifying no more callbacks are active.
54598a978a17SVictor Perevertkin             //
54608a978a17SVictor Perevertkin 
54618a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
54628a978a17SVictor Perevertkin                                 "Power Stop: WDFQUEUE 0x%p is now powered off with no "
54638a978a17SVictor Perevertkin                                 "in-flight requests",GetObjectHandle());
54648a978a17SVictor Perevertkin 
54658a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerOff;
54668a978a17SVictor Perevertkin 
54678a978a17SVictor Perevertkin             m_PowerIdle.Set();
54688a978a17SVictor Perevertkin 
54698a978a17SVictor Perevertkin             return TRUE;
54708a978a17SVictor Perevertkin         }
54718a978a17SVictor Perevertkin 
54728a978a17SVictor Perevertkin         //
54738a978a17SVictor Perevertkin         // The driver has acknowledged all requests, and the
54748a978a17SVictor Perevertkin         // notification list is empty. But, there are still outstanding
54758a978a17SVictor Perevertkin         // dispatch calls into the driver (m_Dispatching != 1), so we potentially
54768a978a17SVictor Perevertkin         // return false here to hopefully unwind to the final dispatch routine,
54778a978a17SVictor Perevertkin         // which will set the power off state.
54788a978a17SVictor Perevertkin         //
54798a978a17SVictor Perevertkin 
54808a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
54818a978a17SVictor Perevertkin                             "Power Stop: Driver has acknowledged all in-flight "
54828a978a17SVictor Perevertkin                             "requests, but WDFQUEUE 0x%p has outstanding callbacks",
54838a978a17SVictor Perevertkin                             GetObjectHandle());
54848a978a17SVictor Perevertkin 
54858a978a17SVictor Perevertkin         return continueProcessing;
54868a978a17SVictor Perevertkin     }
54878a978a17SVictor Perevertkin     case FxIoQueuePowerRestarting:
54888a978a17SVictor Perevertkin 
54898a978a17SVictor Perevertkin         //
54908a978a17SVictor Perevertkin         // Power is being resumed to the device. We notify the
54918a978a17SVictor Perevertkin         // device driver by an event callback for all driver
54928a978a17SVictor Perevertkin         // owned requests that it has idled due to a previous
54938a978a17SVictor Perevertkin         // power stop.
54948a978a17SVictor Perevertkin         //
54958a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerRestartingNotifyingDriver;
54968a978a17SVictor Perevertkin 
54978a978a17SVictor Perevertkin         // This should be empty on entry to this state
54988a978a17SVictor Perevertkin         ASSERT(IsListEmpty(&this->m_PowerNotify));
54998a978a17SVictor Perevertkin 
55008a978a17SVictor Perevertkin         if (!IsListEmpty(&m_DriverOwned)) {
55018a978a17SVictor Perevertkin 
55028a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
55038a978a17SVictor Perevertkin                                 "Power Resume: Driver has power paused requests "
55048a978a17SVictor Perevertkin                                 "on WDFQUEUE 0x%p",GetObjectHandle());
55058a978a17SVictor Perevertkin 
55068a978a17SVictor Perevertkin             // Ensure the logic of m_DriverOwned is correct
55078a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned);
55088a978a17SVictor Perevertkin             ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned);
55098a978a17SVictor Perevertkin 
55108a978a17SVictor Perevertkin             //
55118a978a17SVictor Perevertkin             // Move all requests on m_DriverOwned to m_PowerNotify
55128a978a17SVictor Perevertkin             //
55138a978a17SVictor Perevertkin             m_PowerNotify.Flink = m_DriverOwned.Flink;
55148a978a17SVictor Perevertkin             m_PowerNotify.Blink = m_DriverOwned.Blink;
55158a978a17SVictor Perevertkin             m_PowerNotify.Flink->Blink = &m_PowerNotify;
55168a978a17SVictor Perevertkin             m_PowerNotify.Blink->Flink = &m_PowerNotify;
55178a978a17SVictor Perevertkin 
55188a978a17SVictor Perevertkin             // This is now empty
55198a978a17SVictor Perevertkin             InitializeListHead(&m_DriverOwned);
55208a978a17SVictor Perevertkin         }
55218a978a17SVictor Perevertkin         else {
55228a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
55238a978a17SVictor Perevertkin                                 "Power Resume: Driver has no power paused requests "
55248a978a17SVictor Perevertkin                                 "on WDFQUEUE 0x%p", GetObjectHandle());
55258a978a17SVictor Perevertkin         }
55268a978a17SVictor Perevertkin 
55278a978a17SVictor Perevertkin         //
55288a978a17SVictor Perevertkin         // Return to main processing loop which will callback to
55298a978a17SVictor Perevertkin         // process notifications
55308a978a17SVictor Perevertkin         //
55318a978a17SVictor Perevertkin         return TRUE;
55328a978a17SVictor Perevertkin 
55338a978a17SVictor Perevertkin 
55348a978a17SVictor Perevertkin     case FxIoQueuePowerRestartingNotifyingDriver:  {
55358a978a17SVictor Perevertkin 
55368a978a17SVictor Perevertkin         FxIoQueueIoResume   resumeCallback;
55378a978a17SVictor Perevertkin 
55388a978a17SVictor Perevertkin         //
55398a978a17SVictor Perevertkin         // If the list of requests to notify the driver about is
55408a978a17SVictor Perevertkin         // empty, change to the notified state.
55418a978a17SVictor Perevertkin         //
55428a978a17SVictor Perevertkin         if (IsListEmpty(&m_PowerNotify)) {
55438a978a17SVictor Perevertkin 
55448a978a17SVictor Perevertkin             m_PowerState = FxIoQueuePowerRestartingDriverNotified;
55458a978a17SVictor Perevertkin 
55468a978a17SVictor Perevertkin             //
55478a978a17SVictor Perevertkin             // Return to main processing loop which will callback to
55488a978a17SVictor Perevertkin             // process the next state
55498a978a17SVictor Perevertkin             //
55508a978a17SVictor Perevertkin             return TRUE;
55518a978a17SVictor Perevertkin         }
55528a978a17SVictor Perevertkin 
55538a978a17SVictor Perevertkin         //
55548a978a17SVictor Perevertkin         // Notify each entry in m_PowerNotify into the driver, placing them
55558a978a17SVictor Perevertkin         // back on the m_DriverOwned list.
55568a978a17SVictor Perevertkin         //
55578a978a17SVictor Perevertkin 
55588a978a17SVictor Perevertkin         // Remove from the notify list, place it on the driver owned list
55598a978a17SVictor Perevertkin         Entry = RemoveHeadList(&m_PowerNotify);
55608a978a17SVictor Perevertkin 
55618a978a17SVictor Perevertkin         InsertTailList(&m_DriverOwned, Entry);
55628a978a17SVictor Perevertkin 
55638a978a17SVictor Perevertkin         // Retrieve the FxRequest
55648a978a17SVictor Perevertkin         pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry);
55658a978a17SVictor Perevertkin 
55668a978a17SVictor Perevertkin         resumeCallback = m_IoResume;
55678a978a17SVictor Perevertkin 
55688a978a17SVictor Perevertkin         // Notify driver by callback
55698a978a17SVictor Perevertkin         if (resumeCallback.Method != NULL && pRequest->m_Canceled == FALSE) {
55708a978a17SVictor Perevertkin 
55718a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
55728a978a17SVictor Perevertkin                                 "Power Resume, Notifying Driver, WDFQUEUE 0x%p, "
55738a978a17SVictor Perevertkin                                 "WDFREQUEST 0x%p",
55748a978a17SVictor Perevertkin                                 GetObjectHandle(),
55758a978a17SVictor Perevertkin                                 pRequest->GetObjectHandle());
55768a978a17SVictor Perevertkin 
55778a978a17SVictor Perevertkin             // Driver could be calling RequestComplete as we attempt to resume
55788a978a17SVictor Perevertkin             pRequest->ADDREF(FXREQUEST_HOLD_TAG);
55798a978a17SVictor Perevertkin 
55808a978a17SVictor Perevertkin             Unlock(*PreviousIrql);
55818a978a17SVictor Perevertkin 
55828a978a17SVictor Perevertkin             resumeCallback.Invoke(GetHandle(), pRequest->GetHandle());
55838a978a17SVictor Perevertkin 
55848a978a17SVictor Perevertkin             pRequest->RELEASE(FXREQUEST_HOLD_TAG);
55858a978a17SVictor Perevertkin 
55868a978a17SVictor Perevertkin             Lock(PreviousIrql);
55878a978a17SVictor Perevertkin         }
55888a978a17SVictor Perevertkin         else {
55898a978a17SVictor Perevertkin             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
55908a978a17SVictor Perevertkin                                 "Power Resume: Driver has no callback for "
55918a978a17SVictor Perevertkin                                 "EvtIoResume registered on WDFQUEUE 0x%p",GetObjectHandle());
55928a978a17SVictor Perevertkin         }
55938a978a17SVictor Perevertkin 
55948a978a17SVictor Perevertkin         // Return to main processing loop and continue processing notifications
55958a978a17SVictor Perevertkin         return TRUE;
55968a978a17SVictor Perevertkin     }
55978a978a17SVictor Perevertkin 
55988a978a17SVictor Perevertkin     case FxIoQueuePowerRestartingDriverNotified:
55998a978a17SVictor Perevertkin 
56008a978a17SVictor Perevertkin         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
56018a978a17SVictor Perevertkin                             "Power Resume: WDFQUEUE 0x%p is now powered on and "
56028a978a17SVictor Perevertkin                             "I/O has resumed",GetObjectHandle());
56038a978a17SVictor Perevertkin 
56048a978a17SVictor Perevertkin         // Power state has resumed
56058a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerOn;
56068a978a17SVictor Perevertkin 
56078a978a17SVictor Perevertkin         //
56088a978a17SVictor Perevertkin         // We will resume dispatching I/O after all the queues
56098a978a17SVictor Perevertkin         // are moved into PowerOn state.
56108a978a17SVictor Perevertkin         //
56118a978a17SVictor Perevertkin         return FALSE;
56128a978a17SVictor Perevertkin 
56138a978a17SVictor Perevertkin 
56148a978a17SVictor Perevertkin     default:
56158a978a17SVictor Perevertkin         // Called on invalid state
56168a978a17SVictor Perevertkin         ASSERT(FALSE);
56178a978a17SVictor Perevertkin         return FALSE;
56188a978a17SVictor Perevertkin     }
56198a978a17SVictor Perevertkin 
56208a978a17SVictor Perevertkin     /* NOTREACHED*/
56218a978a17SVictor Perevertkin }
56228a978a17SVictor Perevertkin 
__drv_requiresIRQL(DISPATCH_LEVEL)56238a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
56248a978a17SVictor Perevertkin VOID
56258a978a17SVictor Perevertkin FxIoQueue::ProcessAcknowledgedRequests(
56268a978a17SVictor Perevertkin     __in FxRequest* Request,
56278a978a17SVictor Perevertkin     __out PKIRQL PreviousIrql
56288a978a17SVictor Perevertkin     )
56298a978a17SVictor Perevertkin /*++
56308a978a17SVictor Perevertkin 
56318a978a17SVictor Perevertkin Routine Description:
56328a978a17SVictor Perevertkin 
56338a978a17SVictor Perevertkin     Process requests that are acknowledged by the driver.
56348a978a17SVictor Perevertkin 
56358a978a17SVictor Perevertkin     Called with the queue lock held. This function can drop
56368a978a17SVictor Perevertkin     and reacquire the lock if needed.
56378a978a17SVictor Perevertkin 
56388a978a17SVictor Perevertkin Return Value:
56398a978a17SVictor Perevertkin 
56408a978a17SVictor Perevertkin --*/
56418a978a17SVictor Perevertkin {
56428a978a17SVictor Perevertkin     PLIST_ENTRY Entry;
56438a978a17SVictor Perevertkin     BOOLEAN requeue;
56448a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
56458a978a17SVictor Perevertkin 
56468a978a17SVictor Perevertkin     pFxDriverGlobals = GetDriverGlobals();
56478a978a17SVictor Perevertkin 
56488a978a17SVictor Perevertkin     ASSERT(Request->IsPowerStopAcknowledged());
56498a978a17SVictor Perevertkin 
56508a978a17SVictor Perevertkin     requeue = Request->IsPowerStopAcknowledgedWithRequeue();
56518a978a17SVictor Perevertkin 
56528a978a17SVictor Perevertkin     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
56538a978a17SVictor Perevertkin             "Acknowledging WDFREQUEST %p on WDFQUEUE %p %s requeue option",
56548a978a17SVictor Perevertkin             Request->GetObjectHandle(), GetObjectHandle(),
56558a978a17SVictor Perevertkin             (requeue ? "with" : "without"));
56568a978a17SVictor Perevertkin 
56578a978a17SVictor Perevertkin     Request->ClearPowerStopState();
56588a978a17SVictor Perevertkin 
56598a978a17SVictor Perevertkin     //
56608a978a17SVictor Perevertkin     // Remove the request from the m_PowerDriverNotified list and
56618a978a17SVictor Perevertkin     // place it back on the m_DriverOwned list.
56628a978a17SVictor Perevertkin     //
56638a978a17SVictor Perevertkin     // N.B.  Our caller guarantees that we have already been removed, thus we
56648a978a17SVictor Perevertkin     //       must not explicitly remove here.
56658a978a17SVictor Perevertkin     //
56668a978a17SVictor Perevertkin     Entry = Request->GetListEntry(FxListEntryDriverOwned);
56678a978a17SVictor Perevertkin 
56688a978a17SVictor Perevertkin     InitializeListHead(Entry);
56698a978a17SVictor Perevertkin 
56708a978a17SVictor Perevertkin     InsertTailList(&this->m_DriverOwned, Entry);
56718a978a17SVictor Perevertkin 
56728a978a17SVictor Perevertkin     if (pFxDriverGlobals->FxVerifierOn) {
56738a978a17SVictor Perevertkin         //
56748a978a17SVictor Perevertkin         // As soon as we drop the lock below the request may get completed.
56758a978a17SVictor Perevertkin         // So take an addition reference so that we can safely clear the
56768a978a17SVictor Perevertkin         // flag.
56778a978a17SVictor Perevertkin         //
56788a978a17SVictor Perevertkin         Request->ADDREF(FXREQUEST_HOLD_TAG);
56798a978a17SVictor Perevertkin     }
56808a978a17SVictor Perevertkin 
56818a978a17SVictor Perevertkin     Unlock(*PreviousIrql);
56828a978a17SVictor Perevertkin 
56838a978a17SVictor Perevertkin     if (pFxDriverGlobals->FxVerifierOn) {
56848a978a17SVictor Perevertkin         Request->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT);
56858a978a17SVictor Perevertkin         Request->RELEASE(FXREQUEST_HOLD_TAG);
56868a978a17SVictor Perevertkin     }
56878a978a17SVictor Perevertkin 
56888a978a17SVictor Perevertkin     if (requeue) {
56898a978a17SVictor Perevertkin         FxRequestCompletionState oldState;
56908a978a17SVictor Perevertkin         NTSTATUS status;
56918a978a17SVictor Perevertkin 
56928a978a17SVictor Perevertkin         if (pFxDriverGlobals->FxVerifierOn) {
56938a978a17SVictor Perevertkin             Request->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED |
56948a978a17SVictor Perevertkin                                          FXREQUEST_FLAG_DRIVER_DISPATCH);
56958a978a17SVictor Perevertkin         }
56968a978a17SVictor Perevertkin 
56978a978a17SVictor Perevertkin         //
56988a978a17SVictor Perevertkin         // If the device driver requests it back on the queue, we will place it
56998a978a17SVictor Perevertkin         // on the front and it will be re-delivered in the normal EvtIoDefault, ... path.
57008a978a17SVictor Perevertkin         //
57018a978a17SVictor Perevertkin         // EvtIoResume *will not* be called on power resume for this request.
57028a978a17SVictor Perevertkin         //
57038a978a17SVictor Perevertkin 
57048a978a17SVictor Perevertkin         //
57058a978a17SVictor Perevertkin         // The request has only one reference, held by the completion
57068a978a17SVictor Perevertkin         // callback function. We need to take another one before cancelling
57078a978a17SVictor Perevertkin         // this function, otherwise we will lose the request object
57088a978a17SVictor Perevertkin         //
57098a978a17SVictor Perevertkin         Request->ADDREF(FXREQUEST_STATE_TAG);
57108a978a17SVictor Perevertkin 
57118a978a17SVictor Perevertkin         // Cancel the request complete callback (deletes a reference)
57128a978a17SVictor Perevertkin         oldState = Request->SetCompletionState(FxRequestCompletionStateNone);
57138a978a17SVictor Perevertkin         ASSERT(oldState == FxRequestCompletionStateQueue);
57148a978a17SVictor Perevertkin         UNREFERENCED_PARAMETER(oldState);
57158a978a17SVictor Perevertkin 
57168a978a17SVictor Perevertkin         Lock(PreviousIrql);
57178a978a17SVictor Perevertkin 
57188a978a17SVictor Perevertkin         //
57198a978a17SVictor Perevertkin         // We are going to place the request back on the queue
57208a978a17SVictor Perevertkin         //
57218a978a17SVictor Perevertkin 
57228a978a17SVictor Perevertkin         // Driver is returning I/O
57238a978a17SVictor Perevertkin         RemoveFromDriverOwnedList(Request);
57248a978a17SVictor Perevertkin 
57258a978a17SVictor Perevertkin         //
57268a978a17SVictor Perevertkin         // Check if we need to delete this request.
57278a978a17SVictor Perevertkin         //
57288a978a17SVictor Perevertkin         if (m_CancelDispatchedRequests) {
57298a978a17SVictor Perevertkin             //
57308a978a17SVictor Perevertkin             // Do not requeue this request.
57318a978a17SVictor Perevertkin             //
57328a978a17SVictor Perevertkin             status = STATUS_CANCELLED;
57338a978a17SVictor Perevertkin         }
57348a978a17SVictor Perevertkin         else {
57358a978a17SVictor Perevertkin             //
57368a978a17SVictor Perevertkin             // Place the request back at the head of the main queue
57378a978a17SVictor Perevertkin             // so as not to re-order requests
57388a978a17SVictor Perevertkin             //
57398a978a17SVictor Perevertkin             status = Request->InsertHeadIrpQueue(&m_Queue, NULL);
57408a978a17SVictor Perevertkin         }
57418a978a17SVictor Perevertkin 
57428a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
57438a978a17SVictor Perevertkin 
57448a978a17SVictor Perevertkin             // Request not placed in queue, cancel it
57458a978a17SVictor Perevertkin             ASSERT(status == STATUS_CANCELLED);
57468a978a17SVictor Perevertkin 
57478a978a17SVictor Perevertkin             status = STATUS_SUCCESS;
57488a978a17SVictor Perevertkin 
57498a978a17SVictor Perevertkin             //
57508a978a17SVictor Perevertkin             // We must add a reference since the CancelForQueue path
57518a978a17SVictor Perevertkin             // assumes we were on the FxIrpQueue with the extra reference
57528a978a17SVictor Perevertkin             //
57538a978a17SVictor Perevertkin             Request->ADDREF(FXREQUEST_QUEUE_TAG);
57548a978a17SVictor Perevertkin 
57558a978a17SVictor Perevertkin             //
57568a978a17SVictor Perevertkin             // Mark the request as cancelled, place it on the cancel list,
57578a978a17SVictor Perevertkin             // and schedule the cancel event to the driver
57588a978a17SVictor Perevertkin             //
57598a978a17SVictor Perevertkin             CancelForQueue(Request, *PreviousIrql);
57608a978a17SVictor Perevertkin 
57618a978a17SVictor Perevertkin             //
57628a978a17SVictor Perevertkin             // Reacquire the lock because CancelForQueue visits the dispatch-loop
57638a978a17SVictor Perevertkin             // and releases the lock.
57648a978a17SVictor Perevertkin             //
57658a978a17SVictor Perevertkin             Lock(PreviousIrql);
57668a978a17SVictor Perevertkin         }
57678a978a17SVictor Perevertkin         else {
57688a978a17SVictor Perevertkin             // Check if went from no requests to have requests
57698a978a17SVictor Perevertkin             CheckTransitionFromEmpty();
57708a978a17SVictor Perevertkin         }
57718a978a17SVictor Perevertkin 
57728a978a17SVictor Perevertkin     } else {
57738a978a17SVictor Perevertkin         Lock(PreviousIrql);
57748a978a17SVictor Perevertkin     }
57758a978a17SVictor Perevertkin 
57768a978a17SVictor Perevertkin     return;
57778a978a17SVictor Perevertkin }
57788a978a17SVictor Perevertkin 
57798a978a17SVictor Perevertkin VOID
StartPowerTransitionOff()57808a978a17SVictor Perevertkin FxIoQueue::StartPowerTransitionOff(
57818a978a17SVictor Perevertkin     )
57828a978a17SVictor Perevertkin /*++
57838a978a17SVictor Perevertkin 
57848a978a17SVictor Perevertkin     Routine Description:
57858a978a17SVictor Perevertkin 
57868a978a17SVictor Perevertkin     Purpose of this routine is to put the queue in state that would
57878a978a17SVictor Perevertkin     prevent any new requests from being dispatched to the driver.
57888a978a17SVictor Perevertkin 
57898a978a17SVictor Perevertkin Arguments:
57908a978a17SVictor Perevertkin 
57918a978a17SVictor Perevertkin Return Value:
57928a978a17SVictor Perevertkin 
57938a978a17SVictor Perevertkin     VOID
57948a978a17SVictor Perevertkin 
57958a978a17SVictor Perevertkin --*/
57968a978a17SVictor Perevertkin {
57978a978a17SVictor Perevertkin     KIRQL irql;
57988a978a17SVictor Perevertkin     BOOLEAN result;
57998a978a17SVictor Perevertkin 
58008a978a17SVictor Perevertkin     if(m_PowerManaged == FALSE) {
58018a978a17SVictor Perevertkin         return;
58028a978a17SVictor Perevertkin     }
58038a978a17SVictor Perevertkin 
58048a978a17SVictor Perevertkin     Lock(&irql);
58058a978a17SVictor Perevertkin 
58068a978a17SVictor Perevertkin     if (m_Deleted == FALSE) {
58078a978a17SVictor Perevertkin         ASSERT(m_PowerState == FxIoQueuePowerOn);
58088a978a17SVictor Perevertkin     }
58098a978a17SVictor Perevertkin 
58108a978a17SVictor Perevertkin     m_PowerState = FxIoQueuePowerStartingTransition;
58118a978a17SVictor Perevertkin 
58128a978a17SVictor Perevertkin     // We must wait on the current thread until the queue is actually idle
58138a978a17SVictor Perevertkin     m_PowerIdle.Clear();
58148a978a17SVictor Perevertkin 
58158a978a17SVictor Perevertkin     //
58168a978a17SVictor Perevertkin     // Run the event dispatching loop before waiting on the event
58178a978a17SVictor Perevertkin     // in case this thread actually performs the transition
58188a978a17SVictor Perevertkin     //
58198a978a17SVictor Perevertkin     result = DispatchEvents(irql);
58208a978a17SVictor Perevertkin     if(result) {
58218a978a17SVictor Perevertkin         //
58228a978a17SVictor Perevertkin         // This is called from a kernel mode PNP thread, so we do not need
58238a978a17SVictor Perevertkin         // a KeEnterCriticalRegion()
58248a978a17SVictor Perevertkin         //
58258a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
58268a978a17SVictor Perevertkin                             "Waiting for all threads to stop dispatching requests"
58278a978a17SVictor Perevertkin                             " so that WDFQUEUE 0x%p can be powered off",
58288a978a17SVictor Perevertkin                             GetObjectHandle());
58298a978a17SVictor Perevertkin 
58308a978a17SVictor Perevertkin         GetDriverGlobals()->WaitForSignal(m_PowerIdle.GetSelfPointer(),
58318a978a17SVictor Perevertkin                 "waiting for all threads to stop dispatching requests so "
58328a978a17SVictor Perevertkin                 "that queue can be powered off, WDFQUEUE", GetHandle(),
58338a978a17SVictor Perevertkin                 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
58348a978a17SVictor Perevertkin                 WaitSignalBreakUnderVerifier);
58358a978a17SVictor Perevertkin     }
58368a978a17SVictor Perevertkin 
58378a978a17SVictor Perevertkin     return;
58388a978a17SVictor Perevertkin }
58398a978a17SVictor Perevertkin 
58408a978a17SVictor Perevertkin VOID
StopProcessingForPower(__in FxIoStopProcessingForPowerAction Action)58418a978a17SVictor Perevertkin FxIoQueue::StopProcessingForPower(
58428a978a17SVictor Perevertkin     __in FxIoStopProcessingForPowerAction Action
58438a978a17SVictor Perevertkin     )
58448a978a17SVictor Perevertkin /*++
58458a978a17SVictor Perevertkin 
58468a978a17SVictor Perevertkin     Routine Description:
58478a978a17SVictor Perevertkin 
58488a978a17SVictor Perevertkin     Stops automatic I/O processing due to a power event that requires I/O to stop.
58498a978a17SVictor Perevertkin 
58508a978a17SVictor Perevertkin     This is called on a PASSIVE_LEVEL thread that can block until
58518a978a17SVictor Perevertkin     I/O has been stopped, or completed/cancelled.
58528a978a17SVictor Perevertkin 
58538a978a17SVictor Perevertkin     Additional reference is already taken on the object by the caller
58548a978a17SVictor Perevertkin     to prevent the queue from being deleted.
58558a978a17SVictor Perevertkin 
58568a978a17SVictor Perevertkin 
58578a978a17SVictor Perevertkin Arguments:
58588a978a17SVictor Perevertkin 
58598a978a17SVictor Perevertkin     Action -
58608a978a17SVictor Perevertkin 
58618a978a17SVictor Perevertkin     FxIoStopProcessingForPowerHold:
58628a978a17SVictor Perevertkin     the function returns when the driver has acknowledged that it has
58638a978a17SVictor Perevertkin     stopped all I/O processing, but may have outstanding "in-flight" requests
58648a978a17SVictor Perevertkin     that have not been completed.
58658a978a17SVictor Perevertkin 
58668a978a17SVictor Perevertkin     FxIoStopProcessingForPowerPurgeManaged:
58678a978a17SVictor Perevertkin     the function returns when all requests from a power managed queue have
58688a978a17SVictor Perevertkin     been completed and/or cancelled., and there are no more in-flight requests.
58698a978a17SVictor Perevertkin 
58708a978a17SVictor Perevertkin     FxIoStopProcessingForPowerPurgeNonManaged:
58718a978a17SVictor Perevertkin     the function returns when all requests from a non-power managed queue have
58728a978a17SVictor Perevertkin     been completed and/or cancelled., and there are no more in-flight requests.
58738a978a17SVictor Perevertkin 
58748a978a17SVictor Perevertkin Return Value:
58758a978a17SVictor Perevertkin 
58768a978a17SVictor Perevertkin     NTSTATUS
58778a978a17SVictor Perevertkin 
58788a978a17SVictor Perevertkin --*/
58798a978a17SVictor Perevertkin {
58808a978a17SVictor Perevertkin     KIRQL irql;
58818a978a17SVictor Perevertkin     BOOLEAN result;
58828a978a17SVictor Perevertkin 
58838a978a17SVictor Perevertkin     switch (Action) {
58848a978a17SVictor Perevertkin     case FxIoStopProcessingForPowerPurgeNonManaged:
58858a978a17SVictor Perevertkin 
58868a978a17SVictor Perevertkin         //
58878a978a17SVictor Perevertkin         // If power managed, leave it alone
58888a978a17SVictor Perevertkin         //
58898a978a17SVictor Perevertkin         if(m_PowerManaged == TRUE) {
58908a978a17SVictor Perevertkin             // Should be powered off by now.
58918a978a17SVictor Perevertkin             ASSERT(m_PowerState == FxIoQueuePowerOff);
58928a978a17SVictor Perevertkin             return;
58938a978a17SVictor Perevertkin         }
58948a978a17SVictor Perevertkin 
58958a978a17SVictor Perevertkin         //
58968a978a17SVictor Perevertkin         // Queue is being shut down. This flag prevents the following:
58978a978a17SVictor Perevertkin         // (1) a race condition where a dispatch queue handler changes the
58988a978a17SVictor Perevertkin         //     state of the queue to accept_requests while we are in the
58998a978a17SVictor Perevertkin         //     middle of a power stopping (purge) operation
59008a978a17SVictor Perevertkin 
59018a978a17SVictor Perevertkin         // (2) another thread calling Stop or Start on a queue that is in the
59028a978a17SVictor Perevertkin         //     middle of a power stopping (purge) operation.
59038a978a17SVictor Perevertkin         //
59048a978a17SVictor Perevertkin         Lock(&irql);
59058a978a17SVictor Perevertkin         SetStateForShutdown();
59068a978a17SVictor Perevertkin         Unlock(irql);
59078a978a17SVictor Perevertkin 
59088a978a17SVictor Perevertkin         QueuePurge(TRUE, TRUE, NULL, NULL);
59098a978a17SVictor Perevertkin 
59108a978a17SVictor Perevertkin         Lock(&irql);
59118a978a17SVictor Perevertkin         //
59128a978a17SVictor Perevertkin         // Queue must be in PowerOn state.
59138a978a17SVictor Perevertkin         //
59148a978a17SVictor Perevertkin         ASSERT(m_PowerState == FxIoQueuePowerOn);
59158a978a17SVictor Perevertkin 
59168a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerPurge;
59178a978a17SVictor Perevertkin 
59188a978a17SVictor Perevertkin         break;
59198a978a17SVictor Perevertkin 
59208a978a17SVictor Perevertkin     case FxIoStopProcessingForPowerPurgeManaged:
59218a978a17SVictor Perevertkin 
59228a978a17SVictor Perevertkin         //
59238a978a17SVictor Perevertkin         // If not power managed, leave it alone
59248a978a17SVictor Perevertkin         //
59258a978a17SVictor Perevertkin         if(m_PowerManaged == FALSE) {
59268a978a17SVictor Perevertkin             ASSERT(m_PowerState == FxIoQueuePowerOn);
59278a978a17SVictor Perevertkin             return;
59288a978a17SVictor Perevertkin         }
59298a978a17SVictor Perevertkin 
59308a978a17SVictor Perevertkin         //
59318a978a17SVictor Perevertkin         // Queue is being shut down. This flag prevents the following:
59328a978a17SVictor Perevertkin         // (1) a race condition where a dispatch queue handler changes the
59338a978a17SVictor Perevertkin         //     state of the queue to accept_requests while we are in the
59348a978a17SVictor Perevertkin         //     middle of a power stopping (purge) operation
59358a978a17SVictor Perevertkin 
59368a978a17SVictor Perevertkin         // (2) another thread calling Stop or Start on a queue that is in the
59378a978a17SVictor Perevertkin         //     middle of a power stopping (purge) operation.
59388a978a17SVictor Perevertkin         //
59398a978a17SVictor Perevertkin         Lock(&irql);
59408a978a17SVictor Perevertkin         SetStateForShutdown();
59418a978a17SVictor Perevertkin         Unlock(irql);
59428a978a17SVictor Perevertkin 
59438a978a17SVictor Perevertkin         QueuePurge(TRUE, TRUE, NULL, NULL);
59448a978a17SVictor Perevertkin 
59458a978a17SVictor Perevertkin         Lock(&irql);
59468a978a17SVictor Perevertkin 
59478a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerPurge;
59488a978a17SVictor Perevertkin 
59498a978a17SVictor Perevertkin         break;
59508a978a17SVictor Perevertkin 
59518a978a17SVictor Perevertkin     case FxIoStopProcessingForPowerHold:
59528a978a17SVictor Perevertkin         //
59538a978a17SVictor Perevertkin         // If not power managed, leave it alone
59548a978a17SVictor Perevertkin         //
59558a978a17SVictor Perevertkin         if(m_PowerManaged == FALSE) {
59568a978a17SVictor Perevertkin             ASSERT(m_PowerState == FxIoQueuePowerOn);
59578a978a17SVictor Perevertkin             return;
59588a978a17SVictor Perevertkin         }
59598a978a17SVictor Perevertkin 
59608a978a17SVictor Perevertkin         Lock(&irql);
59618a978a17SVictor Perevertkin 
59628a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerStopping;
59638a978a17SVictor Perevertkin 
59648a978a17SVictor Perevertkin         break;
59658a978a17SVictor Perevertkin 
59668a978a17SVictor Perevertkin     default:
59678a978a17SVictor Perevertkin         ASSERT(FALSE);
59688a978a17SVictor Perevertkin         return;
59698a978a17SVictor Perevertkin     }
59708a978a17SVictor Perevertkin 
59718a978a17SVictor Perevertkin     // We must wait on the current thread until the queue is actually idle
59728a978a17SVictor Perevertkin     m_PowerIdle.Clear();
59738a978a17SVictor Perevertkin 
59748a978a17SVictor Perevertkin     //
59758a978a17SVictor Perevertkin     // Run the event dispatching loop before waiting on the event
59768a978a17SVictor Perevertkin     // in case this thread actually performs the transition
59778a978a17SVictor Perevertkin     //
59788a978a17SVictor Perevertkin     result = DispatchEvents(irql);
59798a978a17SVictor Perevertkin     if(result) {
59808a978a17SVictor Perevertkin         //
59818a978a17SVictor Perevertkin         // This is called from a kernel mode PNP thread, so we do not need
59828a978a17SVictor Perevertkin         // a KeEnterCriticalRegion()
59838a978a17SVictor Perevertkin         //
59848a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
59858a978a17SVictor Perevertkin                             "Waiting for all inflight requests to be acknowledged "
59868a978a17SVictor Perevertkin                             " on WDFQUEUE 0x%p",
59878a978a17SVictor Perevertkin                             GetObjectHandle());
59888a978a17SVictor Perevertkin 
59898a978a17SVictor Perevertkin         GetDriverGlobals()->WaitForSignal(m_PowerIdle.GetSelfPointer(),
59908a978a17SVictor Perevertkin                                 "waiting for all inflight requests "
59918a978a17SVictor Perevertkin                                 "to be acknowledged on WDFQUEUE",
59928a978a17SVictor Perevertkin                                 GetHandle(),
59938a978a17SVictor Perevertkin                                 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
59948a978a17SVictor Perevertkin                                 WaitSignalBreakUnderVerifier);
59958a978a17SVictor Perevertkin     }
59968a978a17SVictor Perevertkin 
59978a978a17SVictor Perevertkin     return;
59988a978a17SVictor Perevertkin }
59998a978a17SVictor Perevertkin 
60008a978a17SVictor Perevertkin VOID
StartPowerTransitionOn(VOID)60018a978a17SVictor Perevertkin FxIoQueue::StartPowerTransitionOn(
60028a978a17SVictor Perevertkin     VOID
60038a978a17SVictor Perevertkin     )
60048a978a17SVictor Perevertkin /*++
60058a978a17SVictor Perevertkin     Routine Description: Start dispatching I/Os
60068a978a17SVictor Perevertkin 
60078a978a17SVictor Perevertkin     Arguments: VOID
60088a978a17SVictor Perevertkin 
60098a978a17SVictor Perevertkin     Return Value:  VOID
60108a978a17SVictor Perevertkin --*/
60118a978a17SVictor Perevertkin {
60128a978a17SVictor Perevertkin     KIRQL irql;
60138a978a17SVictor Perevertkin 
60148a978a17SVictor Perevertkin     if(m_PowerManaged == FALSE) {
60158a978a17SVictor Perevertkin         ASSERT(m_PowerState == FxIoQueuePowerOn);
60168a978a17SVictor Perevertkin         return;
60178a978a17SVictor Perevertkin     }
60188a978a17SVictor Perevertkin 
60198a978a17SVictor Perevertkin     Lock(&irql);
60208a978a17SVictor Perevertkin 
60218a978a17SVictor Perevertkin     if (m_Deleted == FALSE) {
60228a978a17SVictor Perevertkin         ASSERT(m_PowerState == FxIoQueuePowerOn);
60238a978a17SVictor Perevertkin     }
60248a978a17SVictor Perevertkin 
60258a978a17SVictor Perevertkin     //
60268a978a17SVictor Perevertkin     // If there are requests in the queue when we power up, we
60278a978a17SVictor Perevertkin     // should set m_TransitionFromEmpty to trigger event-ready notify
60288a978a17SVictor Perevertkin     // callback on the manual queue to kick start processing of requests.
60298a978a17SVictor Perevertkin     // If we don't set, there is a posibility for abandoning the requests in the
60308a978a17SVictor Perevertkin     // the queue if the queue is powered off between the time we call
60318a978a17SVictor Perevertkin     // ProcessReadNotify and the call to retrieve requests made by the driver
60328a978a17SVictor Perevertkin     // because the retrieve call will fail and the request will be left in the
60338a978a17SVictor Perevertkin     // queue with m_TransitionFromEmpty state cleared.
60348a978a17SVictor Perevertkin     //
60358a978a17SVictor Perevertkin     if (m_Queue.GetRequestCount() > 0L) {
60368a978a17SVictor Perevertkin         m_TransitionFromEmpty = TRUE;
60378a978a17SVictor Perevertkin         m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE;
60388a978a17SVictor Perevertkin     }
60398a978a17SVictor Perevertkin 
60408a978a17SVictor Perevertkin     DispatchEvents(irql);
60418a978a17SVictor Perevertkin 
60428a978a17SVictor Perevertkin     return;
60438a978a17SVictor Perevertkin }
60448a978a17SVictor Perevertkin 
60458a978a17SVictor Perevertkin VOID
ResumeProcessingForPower(VOID)60468a978a17SVictor Perevertkin FxIoQueue::ResumeProcessingForPower(
60478a978a17SVictor Perevertkin     VOID
60488a978a17SVictor Perevertkin     )
60498a978a17SVictor Perevertkin /*++
60508a978a17SVictor Perevertkin 
60518a978a17SVictor Perevertkin     Routine Description:
60528a978a17SVictor Perevertkin 
60538a978a17SVictor Perevertkin     Resumes a PowerManaged queue for automatic I/O processing due to
60548a978a17SVictor Perevertkin     a power event that allows I/O to resume.
60558a978a17SVictor Perevertkin 
60568a978a17SVictor Perevertkin     Does nothing if its a non-power managed queue.
60578a978a17SVictor Perevertkin 
60588a978a17SVictor Perevertkin     Additional reference is already taken on the object by the caller
60598a978a17SVictor Perevertkin     to prevent the queue from being deleted.
60608a978a17SVictor Perevertkin 
60618a978a17SVictor Perevertkin Arguments:
60628a978a17SVictor Perevertkin 
60638a978a17SVictor Perevertkin Return Value:
60648a978a17SVictor Perevertkin 
60658a978a17SVictor Perevertkin     NTSTATUS
60668a978a17SVictor Perevertkin 
60678a978a17SVictor Perevertkin --*/
60688a978a17SVictor Perevertkin {
60698a978a17SVictor Perevertkin     KIRQL irql;
60708a978a17SVictor Perevertkin 
60718a978a17SVictor Perevertkin     //
60728a978a17SVictor Perevertkin     // If not power managed, leave it alone
60738a978a17SVictor Perevertkin     //
60748a978a17SVictor Perevertkin     if (!m_PowerManaged) {
60758a978a17SVictor Perevertkin         ASSERT(m_PowerState == FxIoQueuePowerOn);
60768a978a17SVictor Perevertkin         return;
60778a978a17SVictor Perevertkin     }
60788a978a17SVictor Perevertkin 
60798a978a17SVictor Perevertkin     Lock(&irql);
60808a978a17SVictor Perevertkin 
60818a978a17SVictor Perevertkin     if (m_PowerState == FxIoQueuePowerOn) {
60828a978a17SVictor Perevertkin         Unlock(irql);
60838a978a17SVictor Perevertkin         return;
60848a978a17SVictor Perevertkin     }
60858a978a17SVictor Perevertkin 
60868a978a17SVictor Perevertkin     ASSERT(m_PowerState == FxIoQueuePowerOff);
60878a978a17SVictor Perevertkin 
60888a978a17SVictor Perevertkin     m_PowerState = FxIoQueuePowerRestarting;
60898a978a17SVictor Perevertkin 
60908a978a17SVictor Perevertkin     //
60918a978a17SVictor Perevertkin     // We have transitioned to a status that resumes
60928a978a17SVictor Perevertkin     // processing, so call dispatch function.
60938a978a17SVictor Perevertkin     //
60948a978a17SVictor Perevertkin 
60958a978a17SVictor Perevertkin     DispatchEvents(irql);
60968a978a17SVictor Perevertkin 
60978a978a17SVictor Perevertkin     return;
60988a978a17SVictor Perevertkin }
60998a978a17SVictor Perevertkin 
61008a978a17SVictor Perevertkin VOID
SetStateForShutdown(VOID)61018a978a17SVictor Perevertkin FxIoQueue::SetStateForShutdown(
61028a978a17SVictor Perevertkin     VOID
61038a978a17SVictor Perevertkin     )
61048a978a17SVictor Perevertkin /*++
61058a978a17SVictor Perevertkin 
61068a978a17SVictor Perevertkin Routine Description:
61078a978a17SVictor Perevertkin     The queue is shutting down. Disable WdfQueueStart/Stop from re-enabling
61088a978a17SVictor Perevertkin     the AcceptRequest bit.
61098a978a17SVictor Perevertkin 
61108a978a17SVictor Perevertkin Arguments:
61118a978a17SVictor Perevertkin     None
61128a978a17SVictor Perevertkin 
61138a978a17SVictor Perevertkin Return Value:
61148a978a17SVictor Perevertkin     None
61158a978a17SVictor Perevertkin 
61168a978a17SVictor Perevertkin   --*/
61178a978a17SVictor Perevertkin {
61188a978a17SVictor Perevertkin     //
61198a978a17SVictor Perevertkin     // No need to take a lock since caller is responsible for providing the
61208a978a17SVictor Perevertkin     // required synchronization.
61218a978a17SVictor Perevertkin     //
61228a978a17SVictor Perevertkin 
61238a978a17SVictor Perevertkin     //
61248a978a17SVictor Perevertkin     // Do not allow request to be queued.
61258a978a17SVictor Perevertkin     //
61268a978a17SVictor Perevertkin     SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetShutdown | FxIoQueueClearAcceptRequests));
61278a978a17SVictor Perevertkin }
61288a978a17SVictor Perevertkin 
61298a978a17SVictor Perevertkin VOID
ResetStateForRestart(VOID)61308a978a17SVictor Perevertkin FxIoQueue::ResetStateForRestart(
61318a978a17SVictor Perevertkin     VOID
61328a978a17SVictor Perevertkin     )
61338a978a17SVictor Perevertkin /*++
61348a978a17SVictor Perevertkin 
61358a978a17SVictor Perevertkin Routine Description:
61368a978a17SVictor Perevertkin     This is called on a device (PDO) which has been restarted from the removed
61378a978a17SVictor Perevertkin     state.  It will reset purged queues so that it can accept new requests
61388a978a17SVictor Perevertkin     when ResumeProcessingForPower is called afterwards.
61398a978a17SVictor Perevertkin 
61408a978a17SVictor Perevertkin     Additional reference is already taken on the object by the caller
61418a978a17SVictor Perevertkin     to prevent the queue from being deleted.
61428a978a17SVictor Perevertkin 
61438a978a17SVictor Perevertkin 
61448a978a17SVictor Perevertkin Arguments:
61458a978a17SVictor Perevertkin     None
61468a978a17SVictor Perevertkin 
61478a978a17SVictor Perevertkin Return Value:
61488a978a17SVictor Perevertkin     None
61498a978a17SVictor Perevertkin 
61508a978a17SVictor Perevertkin   --*/
61518a978a17SVictor Perevertkin {
61528a978a17SVictor Perevertkin     KIRQL irql;
61538a978a17SVictor Perevertkin 
61548a978a17SVictor Perevertkin     Lock(&irql);
61558a978a17SVictor Perevertkin 
61568a978a17SVictor Perevertkin     //
61578a978a17SVictor Perevertkin     // For non power managed queues, let us reset the m_PowerState to On
61588a978a17SVictor Perevertkin     //
61598a978a17SVictor Perevertkin     if (!m_PowerManaged) {
61608a978a17SVictor Perevertkin         m_PowerState = FxIoQueuePowerOn;
61618a978a17SVictor Perevertkin     }
61628a978a17SVictor Perevertkin 
61638a978a17SVictor Perevertkin     //
61648a978a17SVictor Perevertkin     // Allow requests to be queued.
61658a978a17SVictor Perevertkin     //
61668a978a17SVictor Perevertkin     SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueClearShutdown | FxIoQueueSetAcceptRequests));
61678a978a17SVictor Perevertkin 
61688a978a17SVictor Perevertkin     //
61698a978a17SVictor Perevertkin     // No need to visit the DispatchEvents because the PowerState
61708a978a17SVictor Perevertkin     // is still off.
61718a978a17SVictor Perevertkin     //
61728a978a17SVictor Perevertkin     Unlock(irql);
61738a978a17SVictor Perevertkin 
61748a978a17SVictor Perevertkin     return;
61758a978a17SVictor Perevertkin }
61768a978a17SVictor Perevertkin 
61778a978a17SVictor Perevertkin BOOLEAN
IsIoEventHandlerRegistered(__in WDF_REQUEST_TYPE RequestType)61788a978a17SVictor Perevertkin FxIoQueue::IsIoEventHandlerRegistered(
61798a978a17SVictor Perevertkin     __in WDF_REQUEST_TYPE RequestType
61808a978a17SVictor Perevertkin     )
61818a978a17SVictor Perevertkin /*++
61828a978a17SVictor Perevertkin 
61838a978a17SVictor Perevertkin Routine Description:
61848a978a17SVictor Perevertkin    Given a request type, this function checks to see if the appropriate
61858a978a17SVictor Perevertkin    event handler is registered to receive dispatched requests.
61868a978a17SVictor Perevertkin 
61878a978a17SVictor Perevertkin Return Value:
61888a978a17SVictor Perevertkin 
61898a978a17SVictor Perevertkin     TRUE - yes the queue is configured to dispatch requests of given RequestType
61908a978a17SVictor Perevertkin     FALSE - no, the queue cannot dispatch requests of given RequestType
61918a978a17SVictor Perevertkin 
61928a978a17SVictor Perevertkin --*/
61938a978a17SVictor Perevertkin {
61948a978a17SVictor Perevertkin     if(m_Type == WdfIoQueueDispatchManual) {
61958a978a17SVictor Perevertkin         //
61968a978a17SVictor Perevertkin         // Manual queues wouldn't have any IoEvent callbacks registered.
61978a978a17SVictor Perevertkin         //
61988a978a17SVictor Perevertkin         return TRUE;
61998a978a17SVictor Perevertkin     }
62008a978a17SVictor Perevertkin 
62018a978a17SVictor Perevertkin     //
62028a978a17SVictor Perevertkin     // Default handler is a catch all handler.
62038a978a17SVictor Perevertkin     //
62048a978a17SVictor Perevertkin     if(m_IoDefault.Method != NULL) {
62058a978a17SVictor Perevertkin         return TRUE;
62068a978a17SVictor Perevertkin     }
62078a978a17SVictor Perevertkin 
62088a978a17SVictor Perevertkin     //
62098a978a17SVictor Perevertkin     // Default handle is not registered. So check to see if request specific
62108a978a17SVictor Perevertkin     // handler is registered.
62118a978a17SVictor Perevertkin     //
62128a978a17SVictor Perevertkin     switch(RequestType) {
62138a978a17SVictor Perevertkin     case WdfRequestTypeRead:
62148a978a17SVictor Perevertkin         if(m_IoRead.Method == NULL) {
62158a978a17SVictor Perevertkin             return FALSE;
62168a978a17SVictor Perevertkin         }
62178a978a17SVictor Perevertkin         break;
62188a978a17SVictor Perevertkin     case WdfRequestTypeWrite:
62198a978a17SVictor Perevertkin         if(m_IoWrite.Method == NULL) {
62208a978a17SVictor Perevertkin             return FALSE;
62218a978a17SVictor Perevertkin         }
62228a978a17SVictor Perevertkin         break;
62238a978a17SVictor Perevertkin     case WdfRequestTypeDeviceControl:
62248a978a17SVictor Perevertkin         if(m_IoDeviceControl.Method == NULL) {
62258a978a17SVictor Perevertkin             return FALSE;
62268a978a17SVictor Perevertkin         }
62278a978a17SVictor Perevertkin         break;
62288a978a17SVictor Perevertkin     case WdfRequestTypeDeviceControlInternal:
62298a978a17SVictor Perevertkin         if(m_IoInternalDeviceControl.Method == NULL) {
62308a978a17SVictor Perevertkin             return FALSE;
62318a978a17SVictor Perevertkin         }
62328a978a17SVictor Perevertkin         break;
62338a978a17SVictor Perevertkin     case WdfRequestTypeCreate: // Fall through. Must have default handler.
62348a978a17SVictor Perevertkin     default:
62358a978a17SVictor Perevertkin         return FALSE;
62368a978a17SVictor Perevertkin     }
62378a978a17SVictor Perevertkin 
62388a978a17SVictor Perevertkin     return TRUE;
62398a978a17SVictor Perevertkin }
62408a978a17SVictor Perevertkin 
62418a978a17SVictor Perevertkin VOID
_DeferredDispatchThreadThunk(__in PVOID Parameter)62428a978a17SVictor Perevertkin FxIoQueue::_DeferredDispatchThreadThunk(
62438a978a17SVictor Perevertkin     __in PVOID Parameter
62448a978a17SVictor Perevertkin     )
62458a978a17SVictor Perevertkin /*++
62468a978a17SVictor Perevertkin 
62478a978a17SVictor Perevertkin Routine Description:
62488a978a17SVictor Perevertkin    Thunk used when requests must be posted to a workitem.
62498a978a17SVictor Perevertkin 
62508a978a17SVictor Perevertkin --*/
62518a978a17SVictor Perevertkin {
62528a978a17SVictor Perevertkin     FxIoQueue* pQueue = (FxIoQueue*)Parameter;
62538a978a17SVictor Perevertkin 
62548a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = pQueue->GetDriverGlobals();
62558a978a17SVictor Perevertkin 
62568a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
62578a978a17SVictor Perevertkin                         "Dispatching requests from worker thread");
62588a978a17SVictor Perevertkin 
62598a978a17SVictor Perevertkin     pQueue->DeferredDispatchRequestsFromWorkerThread();
62608a978a17SVictor Perevertkin 
62618a978a17SVictor Perevertkin     return;
62628a978a17SVictor Perevertkin }
62638a978a17SVictor Perevertkin 
62648a978a17SVictor Perevertkin 
62658a978a17SVictor Perevertkin VOID
_DeferredDispatchDpcThunk(__in PKDPC Dpc,__in PVOID DeferredContext,__in PVOID SystemArgument1,__in PVOID SystemArgument2)62668a978a17SVictor Perevertkin FxIoQueue::_DeferredDispatchDpcThunk(
62678a978a17SVictor Perevertkin     __in PKDPC Dpc,
62688a978a17SVictor Perevertkin     __in PVOID DeferredContext,
62698a978a17SVictor Perevertkin     __in PVOID SystemArgument1,
62708a978a17SVictor Perevertkin     __in PVOID SystemArgument2
62718a978a17SVictor Perevertkin     )
62728a978a17SVictor Perevertkin /*++
62738a978a17SVictor Perevertkin 
62748a978a17SVictor Perevertkin Routine Description:
62758a978a17SVictor Perevertkin    Thunk used when requests must be posted to a DPC.
62768a978a17SVictor Perevertkin 
62778a978a17SVictor Perevertkin --*/
62788a978a17SVictor Perevertkin {
62798a978a17SVictor Perevertkin     FxIoQueue* pQueue = (FxIoQueue*)DeferredContext;
62808a978a17SVictor Perevertkin 
62818a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS FxDriverGlobals = pQueue->GetDriverGlobals();
62828a978a17SVictor Perevertkin 
62838a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(Dpc);
62848a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(SystemArgument1);
62858a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(SystemArgument2);
62868a978a17SVictor Perevertkin 
62878a978a17SVictor Perevertkin     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
62888a978a17SVictor Perevertkin                         "Dispatching requests from DPC");
62898a978a17SVictor Perevertkin 
62908a978a17SVictor Perevertkin     pQueue->DeferredDispatchRequestsFromDpc();
62918a978a17SVictor Perevertkin 
62928a978a17SVictor Perevertkin     return;
62938a978a17SVictor Perevertkin }
62948a978a17SVictor Perevertkin 
62958a978a17SVictor Perevertkin VOID
_PurgeComplete(__in WDFQUEUE Queue,__in WDFCONTEXT Context)62968a978a17SVictor Perevertkin FxIoQueue::_PurgeComplete(
62978a978a17SVictor Perevertkin     __in WDFQUEUE       Queue,
62988a978a17SVictor Perevertkin     __in WDFCONTEXT        Context
62998a978a17SVictor Perevertkin     )
63008a978a17SVictor Perevertkin /*++
63018a978a17SVictor Perevertkin 
63028a978a17SVictor Perevertkin Routine Description:
63038a978a17SVictor Perevertkin    Callback function when a queue purge completes
63048a978a17SVictor Perevertkin 
63058a978a17SVictor Perevertkin --*/
63068a978a17SVictor Perevertkin {
63078a978a17SVictor Perevertkin     MxEvent* event = (MxEvent*)Context;
63088a978a17SVictor Perevertkin 
63098a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(Queue);
63108a978a17SVictor Perevertkin 
63118a978a17SVictor Perevertkin     event->SetWithIncrement(EVENT_INCREMENT);
63128a978a17SVictor Perevertkin 
63138a978a17SVictor Perevertkin     return;
63148a978a17SVictor Perevertkin }
63158a978a17SVictor Perevertkin 
63168a978a17SVictor Perevertkin VOID
_IdleComplete(__in WDFQUEUE Queue,__in WDFCONTEXT Context)63178a978a17SVictor Perevertkin FxIoQueue::_IdleComplete(
63188a978a17SVictor Perevertkin     __in WDFQUEUE       Queue,
63198a978a17SVictor Perevertkin     __in WDFCONTEXT     Context
63208a978a17SVictor Perevertkin     )
63218a978a17SVictor Perevertkin /*++
63228a978a17SVictor Perevertkin 
63238a978a17SVictor Perevertkin Routine Description:
63248a978a17SVictor Perevertkin    Callback function when a stop completes
63258a978a17SVictor Perevertkin 
63268a978a17SVictor Perevertkin --*/
63278a978a17SVictor Perevertkin {
63288a978a17SVictor Perevertkin     MxEvent* event = (MxEvent*)Context;
63298a978a17SVictor Perevertkin 
63308a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(Queue);
63318a978a17SVictor Perevertkin 
63328a978a17SVictor Perevertkin     event->SetWithIncrement(EVENT_INCREMENT);
63338a978a17SVictor Perevertkin 
63348a978a17SVictor Perevertkin     return;
63358a978a17SVictor Perevertkin }
63368a978a17SVictor Perevertkin 
6337*1f377076SVictor Perevertkin DECLSPEC_NORETURN
63388a978a17SVictor Perevertkin VOID
FatalError(__in NTSTATUS Status)63398a978a17SVictor Perevertkin FxIoQueue::FatalError(
63408a978a17SVictor Perevertkin     __in NTSTATUS Status
63418a978a17SVictor Perevertkin     )
63428a978a17SVictor Perevertkin {
63438a978a17SVictor Perevertkin     WDF_QUEUE_FATAL_ERROR_DATA data;
63448a978a17SVictor Perevertkin 
63458a978a17SVictor Perevertkin     RtlZeroMemory(&data, sizeof(data));
63468a978a17SVictor Perevertkin 
63478a978a17SVictor Perevertkin     data.Queue = GetHandle();
63488a978a17SVictor Perevertkin     data.Request = NULL;
63498a978a17SVictor Perevertkin     data.Status = Status;
63508a978a17SVictor Perevertkin 
63518a978a17SVictor Perevertkin     FxVerifierBugCheck(GetDriverGlobals(),
63528a978a17SVictor Perevertkin                        WDF_QUEUE_FATAL_ERROR,
63538a978a17SVictor Perevertkin                        (ULONG_PTR) &data);
63548a978a17SVictor Perevertkin }
63558a978a17SVictor Perevertkin 
63568a978a17SVictor Perevertkin 
63578a978a17SVictor Perevertkin _Must_inspect_result_
63588a978a17SVictor Perevertkin NTSTATUS
AllocateReservedRequest(__deref_out FxRequest ** Request)63598a978a17SVictor Perevertkin FxIoQueue::AllocateReservedRequest(
63608a978a17SVictor Perevertkin     __deref_out FxRequest** Request
63618a978a17SVictor Perevertkin     )
63628a978a17SVictor Perevertkin /*++
63638a978a17SVictor Perevertkin 
63648a978a17SVictor Perevertkin Routine Description:
63658a978a17SVictor Perevertkin     Called by Fxpkgio::Dispatch to allocate a reserved request if one is
63668a978a17SVictor Perevertkin      avaialble.
63678a978a17SVictor Perevertkin 
63688a978a17SVictor Perevertkin --*/
63698a978a17SVictor Perevertkin 
63708a978a17SVictor Perevertkin {
63718a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS      pFxDriverGlobals;
63728a978a17SVictor Perevertkin     NTSTATUS                status;
63738a978a17SVictor Perevertkin     FxRequest*              pRequest;
63748a978a17SVictor Perevertkin     PWDF_OBJECT_ATTRIBUTES  reqAttribs;
63758a978a17SVictor Perevertkin 
63768a978a17SVictor Perevertkin     pFxDriverGlobals = GetDriverGlobals();
63778a978a17SVictor Perevertkin     *Request = NULL;
63788a978a17SVictor Perevertkin     reqAttribs = NULL;
63798a978a17SVictor Perevertkin 
63808a978a17SVictor Perevertkin     //
63818a978a17SVictor Perevertkin     // Get the right context for this request object.
63828a978a17SVictor Perevertkin     //
63838a978a17SVictor Perevertkin     if (GetCxDeviceInfo() != NULL) {
63848a978a17SVictor Perevertkin         reqAttribs = &GetCxDeviceInfo()->RequestAttributes;
63858a978a17SVictor Perevertkin     }
63868a978a17SVictor Perevertkin     else {
63878a978a17SVictor Perevertkin         reqAttribs = m_Device->GetRequestAttributes();
63888a978a17SVictor Perevertkin     }
63898a978a17SVictor Perevertkin 
63908a978a17SVictor Perevertkin     //
63918a978a17SVictor Perevertkin     // FxRequest::_Create doesn't create a Request from the Device lookaside
63928a978a17SVictor Perevertkin     // hence we can't use that as the Request Context doesn't get associated
63938a978a17SVictor Perevertkin     // if the Request is not created from the lookaside.
63948a978a17SVictor Perevertkin     //
63958a978a17SVictor Perevertkin     status = FxRequest::_CreateForPackage(m_Device, reqAttribs, NULL, &pRequest);
63968a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
63978a978a17SVictor Perevertkin         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
63988a978a17SVictor Perevertkin                             "Failure to allocate request %!STATUS!", status);
63998a978a17SVictor Perevertkin         return status;
64008a978a17SVictor Perevertkin     }
64018a978a17SVictor Perevertkin 
64028a978a17SVictor Perevertkin     pRequest->SetReserved();
64038a978a17SVictor Perevertkin     pRequest->SetCurrentQueue(this);
64048a978a17SVictor Perevertkin 
64058a978a17SVictor Perevertkin     //
64068a978a17SVictor Perevertkin     // This is used to return the request to the correct queue if it was
64078a978a17SVictor Perevertkin     // forwarded
64088a978a17SVictor Perevertkin     //
64098a978a17SVictor Perevertkin     pRequest->SetForwardProgressQueue(this);
64108a978a17SVictor Perevertkin     pRequest->SetCompleted(FALSE);
64118a978a17SVictor Perevertkin 
64128a978a17SVictor Perevertkin     if (m_FwdProgContext->m_IoReservedResourcesAllocate.Method != NULL) {
64138a978a17SVictor Perevertkin 
64148a978a17SVictor Perevertkin         pRequest->SetPresented();
64158a978a17SVictor Perevertkin 
64168a978a17SVictor Perevertkin         status = m_FwdProgContext->m_IoReservedResourcesAllocate.Invoke(
64178a978a17SVictor Perevertkin                                     GetHandle(),
64188a978a17SVictor Perevertkin                                     pRequest->GetHandle());
64198a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
64208a978a17SVictor Perevertkin             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
64218a978a17SVictor Perevertkin                     "Failure from m_IoReservedResourcesAllocate callback %!STATUS!",
64228a978a17SVictor Perevertkin                     status);
64238a978a17SVictor Perevertkin             pRequest->FreeRequest();
64248a978a17SVictor Perevertkin         }
64258a978a17SVictor Perevertkin     }
64268a978a17SVictor Perevertkin 
64278a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
64288a978a17SVictor Perevertkin         *Request = pRequest;
64298a978a17SVictor Perevertkin     }
64308a978a17SVictor Perevertkin 
64318a978a17SVictor Perevertkin     return status;
64328a978a17SVictor Perevertkin }
64338a978a17SVictor Perevertkin 
64348a978a17SVictor Perevertkin 
64358a978a17SVictor Perevertkin VOID
CancelIrps(__in PLIST_ENTRY IrpListHead)64368a978a17SVictor Perevertkin FxIoQueue::CancelIrps(
64378a978a17SVictor Perevertkin     __in PLIST_ENTRY    IrpListHead
64388a978a17SVictor Perevertkin     )
64398a978a17SVictor Perevertkin /*++
64408a978a17SVictor Perevertkin 
64418a978a17SVictor Perevertkin Routine Description:
64428a978a17SVictor Perevertkin 
64438a978a17SVictor Perevertkin     This function is called to purge (cancel) the specified list of IRPs.
64448a978a17SVictor Perevertkin     The IRP's Tail.Overlay.ListEntry field must be used to link these structs together.
64458a978a17SVictor Perevertkin 
64468a978a17SVictor Perevertkin --*/
64478a978a17SVictor Perevertkin {
64488a978a17SVictor Perevertkin     MdIrp        irp;
64498a978a17SVictor Perevertkin     FxIrp        fxIrp;
64508a978a17SVictor Perevertkin     PLIST_ENTRY entry;
64518a978a17SVictor Perevertkin 
64528a978a17SVictor Perevertkin     while(!IsListEmpty(IrpListHead)) {
64538a978a17SVictor Perevertkin 
64548a978a17SVictor Perevertkin         entry = RemoveHeadList(IrpListHead);
64558a978a17SVictor Perevertkin 
64568a978a17SVictor Perevertkin         irp = fxIrp.GetIrpFromListEntry(entry);
64578a978a17SVictor Perevertkin 
64588a978a17SVictor Perevertkin         fxIrp.SetIrp(irp);
64598a978a17SVictor Perevertkin 
64608a978a17SVictor Perevertkin         fxIrp.SetInformation(0);
64618a978a17SVictor Perevertkin         fxIrp.SetStatus(STATUS_CANCELLED);
64628a978a17SVictor Perevertkin         fxIrp.CompleteRequest(IO_NO_INCREMENT);
64638a978a17SVictor Perevertkin     }
64648a978a17SVictor Perevertkin }
64658a978a17SVictor Perevertkin 
64668a978a17SVictor Perevertkin VOID
PurgeForwardProgressIrps(__in_opt MdFileObject FileObject)64678a978a17SVictor Perevertkin FxIoQueue::PurgeForwardProgressIrps(
64688a978a17SVictor Perevertkin     __in_opt MdFileObject FileObject
64698a978a17SVictor Perevertkin     )
64708a978a17SVictor Perevertkin /*++
64718a978a17SVictor Perevertkin 
64728a978a17SVictor Perevertkin Routine Description:
64738a978a17SVictor Perevertkin 
64748a978a17SVictor Perevertkin     This function is called when the queue is purged.
64758a978a17SVictor Perevertkin 
64768a978a17SVictor Perevertkin --*/
64778a978a17SVictor Perevertkin {
64788a978a17SVictor Perevertkin     LIST_ENTRY  cleanupList;
64798a978a17SVictor Perevertkin 
64808a978a17SVictor Perevertkin     InitializeListHead(&cleanupList);
64818a978a17SVictor Perevertkin     GetForwardProgressIrps(&cleanupList, FileObject);
64828a978a17SVictor Perevertkin     CancelIrps(&cleanupList);
64838a978a17SVictor Perevertkin }
64848a978a17SVictor Perevertkin 
64858a978a17SVictor Perevertkin VOID
VerifierVerifyFwdProgListsLocked(VOID)64868a978a17SVictor Perevertkin FxIoQueue::VerifierVerifyFwdProgListsLocked(
64878a978a17SVictor Perevertkin     VOID
64888a978a17SVictor Perevertkin     )
64898a978a17SVictor Perevertkin /*++
64908a978a17SVictor Perevertkin 
64918a978a17SVictor Perevertkin Routine Description:
64928a978a17SVictor Perevertkin     Called from dispose to Free all the reserved requests.
64938a978a17SVictor Perevertkin 
64948a978a17SVictor Perevertkin --*/
64958a978a17SVictor Perevertkin {
64968a978a17SVictor Perevertkin     ULONG countOfInUseRequests;
64978a978a17SVictor Perevertkin     ULONG countOfFreeRequests;
64988a978a17SVictor Perevertkin     PLIST_ENTRY thisEntry, nextEntry, listHead;
64998a978a17SVictor Perevertkin 
65008a978a17SVictor Perevertkin     countOfInUseRequests = 0;
65018a978a17SVictor Perevertkin 
65028a978a17SVictor Perevertkin     listHead = &m_FwdProgContext->m_ReservedRequestInUseList;
65038a978a17SVictor Perevertkin 
65048a978a17SVictor Perevertkin     for(thisEntry = listHead->Flink;
65058a978a17SVictor Perevertkin         thisEntry != listHead;
65068a978a17SVictor Perevertkin         thisEntry = nextEntry)
65078a978a17SVictor Perevertkin     {
65088a978a17SVictor Perevertkin         nextEntry = thisEntry->Flink;
65098a978a17SVictor Perevertkin         countOfInUseRequests++;
65108a978a17SVictor Perevertkin     }
65118a978a17SVictor Perevertkin 
65128a978a17SVictor Perevertkin     countOfFreeRequests = 0;
65138a978a17SVictor Perevertkin 
65148a978a17SVictor Perevertkin     listHead = &m_FwdProgContext->m_ReservedRequestList;
65158a978a17SVictor Perevertkin 
65168a978a17SVictor Perevertkin     for(thisEntry = listHead->Flink;
65178a978a17SVictor Perevertkin         thisEntry != listHead;
65188a978a17SVictor Perevertkin         thisEntry = nextEntry)
65198a978a17SVictor Perevertkin     {
65208a978a17SVictor Perevertkin         nextEntry = thisEntry->Flink;
65218a978a17SVictor Perevertkin         countOfFreeRequests++;
65228a978a17SVictor Perevertkin     }
65238a978a17SVictor Perevertkin 
65248a978a17SVictor Perevertkin     ASSERT(countOfFreeRequests + countOfInUseRequests ==
65258a978a17SVictor Perevertkin            m_FwdProgContext->m_NumberOfReservedRequests);
65268a978a17SVictor Perevertkin     return;
65278a978a17SVictor Perevertkin }
6528