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