static VOID GetIoQueueList_ProcessQueueListEntry( PLIST_ENTRY QueueLE, PSINGLE_LIST_ENTRY SListHead, PVOID Tag ) { FxIoQueueNode* listNode; FxIoQueue* queue; // // Skip any nodes that are not queues. They can be bookmarks for // in-progress flush operations. // listNode = FxIoQueueNode::_FromListEntry(QueueLE); if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { return; } queue = FxIoQueue::_FromIoPkgListEntry(QueueLE); PushEntryList(SListHead, &queue->m_PowerSListEntry); // // Add a reference since the request will be touched outside of the // lock being held. We will use the enumerant value as the tag. // queue->ADDREF(Tag); }
VOID FxPkgIo::AddIoQueue( __inout FxIoQueue* IoQueue ) { PLIST_ENTRY listHead, le; FxIoQueue* queue; KIRQL irql; FxIoQueueNode* listNode; CCHAR queueIndex, curIndex; listHead = &m_IoQueueListHead; queueIndex = FxDevice::GetCxDriverIndex(IoQueue->GetCxDeviceInfo()); Lock(&irql); ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); // // Insert new queue in sorted list; search from last to first. // for (le = listHead->Blink; le != listHead; le = le->Blink) { // // Skip any nodes that are not queues. They can be bookmarks for // in-progress flush operations. // listNode = FxIoQueueNode::_FromListEntry(le); if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { continue; } // // Get current queue's driver index. // queue = FxIoQueue::_FromIoPkgListEntry(le); curIndex = FxDevice::GetCxDriverIndex(queue->GetCxDeviceInfo()); // // Queues are inserted in order at the end of its allowed range. // if (curIndex < queueIndex || curIndex == queueIndex) { break; } } InsertHeadList(le, &IoQueue->m_IoPkgListNode.m_ListEntry); if (m_PowerStateOn) { IoQueue->SetPowerState(FxIoQueuePowerOn); } else { IoQueue->SetPowerState(FxIoQueuePowerOff); if (m_QueuesAreShuttingDown) { // Clear accept requests IoQueue->SetStateForShutdown(); } } Unlock(irql); return; }
VOID FxPkgIo::ResetStateForRestart( VOID ) /*++ Routine Description: This is called on a device which has been restarted from the removed state. It will reset purged queues so that they can accept new requests when ResumeProcessingForPower is called afterwards. Arguments: None Return Value: None --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Restart queues from purged state for WDFDEVICE 0x%p due to " "device restart", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); Unlock(irql); for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResetStateForRestart(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } Lock(&irql); m_PowerStateOn = TRUE; m_QueuesAreShuttingDown = FALSE; Unlock(irql); return; }
FxIoQueue* FxPkgIo::GetNextIoQueueLocked( __in FxIoQueueNode* QueueBookmark, __in PVOID Tag ) /*++ Routine Description: Moves the provided bookmark ahead in the IO Package's queue list and returns the next available queue (if any). Return Value: NULL if there are no more queues in list else FxIoQueue* reference to the next queue in list. --*/ { PLIST_ENTRY ple = NULL; FxIoQueue* queue = NULL; FxIoQueueNode* listNode = NULL; ASSERT(QueueBookmark->IsNodeType(FxIoQueueNodeTypeBookmark)); ASSERT(IsListEmpty(&QueueBookmark->m_ListEntry) == FALSE); // // Try to advance bookmark to next location. // ple = QueueBookmark->m_ListEntry.Flink; RemoveEntryList(&QueueBookmark->m_ListEntry); InitializeListHead(&QueueBookmark->m_ListEntry); for (; ple != &m_IoQueueListHead; ple = ple->Flink) { // // Skip any nodes that are not queues. These nodes can be // bookmarks for in-progress flush operations. // listNode = FxIoQueueNode::_FromListEntry(ple); if (listNode->IsNodeType(FxIoQueueNodeTypeQueue)) { // // This entry is a real queue. // queue = FxIoQueue::_FromIoPkgListEntry(ple); queue->ADDREF(Tag); // // Insert bookmark after this entry. // InsertHeadList(ple, &QueueBookmark->m_ListEntry); break; } } return queue; }
_Must_inspect_result_ NTSTATUS FxPkgIo::FlushAllQueuesByFileObject( __in MdFileObject FileObject ) /*++ Routine Description: Enumerate all the queues and cancel the requests that have the same fileobject as the Cleanup IRP. We are making an assumption that cleanup irps are sent only at passive-level. Return Value: NTSTATUS --*/ { FxIoQueue* queue = NULL; PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); FxIoQueueNode flushBookmark(FxIoQueueNodeTypeBookmark); KIRQL irql; if(Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) { DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Currently framework allow flushing of queues " "by fileobject on cleanup only at PASSIVE_LEVEL"); FxVerifierDbgBreakPoint(pFxDriverGlobals); return STATUS_SUCCESS; } // // Iterate through the queue list and flush each one. // Lock(&irql); queue = GetFirstIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); Unlock(irql); while(queue != NULL) { queue->FlushByFileObject(FileObject); queue->RELEASE(IO_ITERATOR_FLUSH_TAG); Lock(&irql); queue = GetNextIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); Unlock(irql); } return STATUS_SUCCESS; }
NTSTATUS WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDEVICE Device, __in MdIrp Irp, __in WDFQUEUE Queue, __in ULONG Flags ) { FxIoQueue *queue; FxDevice *device; PFX_DRIVER_GLOBALS fxDriverGlobals; PIO_STACK_LOCATION stack; NTSTATUS status; FxIoInCallerContext* ioInCallerCtx; queue = NULL; ioInCallerCtx = NULL; FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Device, FX_TYPE_DEVICE, (PVOID*) &device); fxDriverGlobals = device->GetDriverGlobals(); FX_TRACK_DRIVER(fxDriverGlobals); FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Queue, FX_TYPE_QUEUE, (PVOID*)&queue); FxPointerNotNull(fxDriverGlobals, Irp); // // If the caller is a preprocess routine, the contract for this DDI is just like IoCallDriver. // The caller sets up their stack location and then the DDI advances to the next stack // location. This means that the caller either has to call IoSkipCurrentIrpStackLocation // or IoCopyCurrentIrpStackLocationToNext before calling this DDI. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) { IoSetNextIrpStackLocation(Irp); } // // Verifier checks. // status = VerifyWdfDeviceWdmDispatchIrpToIoQueue(fxDriverGlobals, device, Irp, queue, Flags); if(!NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // // Adjust stack if IRP needs to be forwarded to parent device. // if (device->m_ParentDevice == queue->GetDevice()) { IoCopyCurrentIrpStackLocationToNext(Irp); IoSetNextIrpStackLocation(Irp); // // From now on use new device. // device = device->m_ParentDevice; // // Save a pointer to the device object for this request so that it can // be used later in completion. // stack = IoGetCurrentIrpStackLocation(Irp); stack->DeviceObject = device->GetDeviceObject(); } // // Get in-context caller callback if required. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK) { ioInCallerCtx = device->m_PkgIo->GetIoInCallerContextCallback( queue->GetCxDeviceInfo()); } // // DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if // possible dispatch the request to the driver. // return device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue); }
VOID FxIoTargetSelf::Send( _In_ MdIrp Irp ) /*++ Routine Description: send an MdIrp to the Self IO Target. Arguments: MdIrp for IRP_MJ_READ, IRP_MJ_WRITE, or IRP_MJ_DEVICE_CONTROL Returns: VOID Implementation Note: Function body inspired by WdfDeviceWdmDispatchIrpToIoQueue API. --*/ { FxIrp irp(Irp); FxIoQueue* queue; NTSTATUS status; UCHAR majorFunction; FxIoInCallerContext* ioInCallerCtx; #if (FX_CORE_MODE == FX_CORE_USER_MODE) // // Prepare the request to forward to the inteternal target. // (static_cast<IWudfIoIrp2*>(Irp))->PrepareToForwardToSelf(); #else // // Set Next Stack Location // irp.SetNextIrpStackLocation(); // // Set Device Object. // irp.SetCurrentDeviceObject(m_Device->GetDeviceObject()); #endif majorFunction = irp.GetMajorFunction(); // // Retrieve Queue // queue = GetDispatchQueue(majorFunction); if (queue == NULL) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Send WDFIOTARGET %p, No Dispatch Queue Found for Major Function %d", GetObjectHandle(), majorFunction); status = STATUS_INVALID_DEVICE_STATE; goto Fail; } // // Only read/writes/ctrls/internal_ctrls IRPs are allowed to be sent to // Self IO Target // if (m_Device->GetDispatchPackage(majorFunction) != m_Device->m_PkgIo) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Only Read/Write/Control/Internal-Control IRPs can be " "forwarded to Self IO Target 0x%p, %!IRPMJ!, " "IRP_MN %x, Device 0x%p, %!STATUS!", GetHandle(), majorFunction, irp.GetMinorFunction(), m_Device->GetObjectHandle(), status); FxVerifierDbgBreakPoint(GetDriverGlobals()); goto Fail; } // // Retrieve the InContextCallback function // ioInCallerCtx = m_Device->m_PkgIo->GetIoInCallerContextCallback( queue->GetCxDeviceInfo()); // // DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if // possible dispatch the request to the driver. // If a failure occurs, DispatchStep2 completes teh Irp // (VOID) m_Device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue); return; Fail: irp.SetStatus(status); irp.SetInformation(0); irp.CompleteRequest(IO_NO_INCREMENT); return; }
_Must_inspect_result_ NTSTATUS FxPkgIo::CreateQueue( __in PWDF_IO_QUEUE_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, __in_opt FxDriver* Caller, __deref_out FxIoQueue** ppQueue ) { PFX_DRIVER_GLOBALS pFxDriverGlobals; FxObject* pParent; FxIoQueue* pQueue; NTSTATUS status; FxDriver* pDriver; pParent = NULL; pQueue = NULL; pDriver = NULL; pFxDriverGlobals = GetDriverGlobals(); if (QueueAttributes != NULL && QueueAttributes->ParentObject != NULL) { CfxDeviceBase* pSearchDevice; FxObjectHandleGetPtr(pFxDriverGlobals, QueueAttributes->ParentObject, FX_TYPE_OBJECT, (PVOID*)&pParent); pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL); if (pSearchDevice == NULL) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "QueueAttributes->ParentObject 0x%p must have WDFDEVICE as an " "eventual ancestor, %!STATUS!", QueueAttributes->ParentObject, status); return status; } else if (pSearchDevice != m_DeviceBase) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " "not the same WDFDEVICE 0x%p passed to WdfIoQueueCreate, " "%!STATUS!", QueueAttributes->ParentObject, pSearchDevice->GetHandle(), m_Device->GetHandle(), status); return status; } } else { // // By default, use the package as the parent // pParent = this; } // // v1.11 and up: get driver object if driver handle is specified. // Client driver can also specify a driver handle, the end result in this case is // a PkgIoContext that is NULL (see below), i.e., the same as if driver handle // was NULL. // if (Config->Size > sizeof(WDF_IO_QUEUE_CONFIG_V1_9) && Config->Driver != NULL) { FxObjectHandleGetPtr(GetDriverGlobals(), Config->Driver, FX_TYPE_DRIVER, (PVOID*)&pDriver); } status = FxIoQueue::_Create(pFxDriverGlobals, QueueAttributes, Config, Caller, this, m_PowerStateOn, &pQueue ); if (!NT_SUCCESS(status)) { ASSERT(pQueue == NULL); return status; } // // Class extension support: associate queue with a specific cx layer. // if (pDriver != NULL) { pQueue->SetCxDeviceInfo(m_Device->GetCxDeviceInfo(pDriver)); } status = pQueue->Commit(QueueAttributes, NULL, pParent); if (!NT_SUCCESS(status)) { pQueue->DeleteFromFailedCreate(); return status; } AddIoQueue(pQueue); *ppQueue = pQueue; return status; }
// // This inserts a request into the I/O processing pipeline // _Must_inspect_result_ NTSTATUS FxPkgIo::EnqueueRequest( __in CfxDevice* Device, __inout FxRequest* pRequest ) { NTSTATUS status; FxIoQueue* pQueue; FxIrp* Irp = NULL; FxRequestCompletionState oldState; PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); SHORT origVerifierFlags = 0; // // Request is owned by the driver, and has a reference count of == 1 // (or > 1 if EvtIoInCallerContext callback took an additional reference), // with a FxPkgIoInProcessRequestComplete callback registered. // ASSERT(pRequest->GetRefCnt() >= 1); Irp = pRequest->GetFxIrp(); DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, "WDFREQUEST 0x%p", pRequest->GetObjectHandle()); status = VerifyEnqueueRequestUpdateFlags(FxDriverGlobals, pRequest, &origVerifierFlags); if (!NT_SUCCESS(status)) { return status; } // // Get the associated queue // pQueue = (FxIoQueue*) pRequest->GetInternalContext(); if (NULL == pQueue) { pQueue = m_DispatchTable[Irp->GetMajorFunction()]; if (pQueue == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, " "failing WDFREQUEST 0x%p %!STATUS!", Device->GetHandle(), pRequest->GetObjectHandle(), status); FxVerifierDbgBreakPoint(FxDriverGlobals); // // Return it back to the driver to decide the outcome // goto Error; } } // // If the queue is a default-queue and driver is a filter then before // calling the queue we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. if (m_Filter && pQueue == m_DefaultQueue && pQueue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)Irp->GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } pQueue->AddRef(); // Must add a reference before releasing the callback and its reference pRequest->ADDREF(FXREQUEST_STATE_TAG); // Release the callback oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone); ASSERT(oldState != FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); status = pQueue->QueueRequestFromForward(pRequest); pQueue->Release(); // // If not successfull, must place the request back // to the state it was in on entry so that the driver // can decide what to do next with it // if (!NT_SUCCESS(status)) { // // If the request comes back to us, it should still // have a reference count of 1 // oldState = pRequest->SetCompletionState(FxRequestCompletionStateIoPkg); ASSERT(oldState == FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); // // Release the reference count on the request since // the callback will hold the only one that gets // decremented when the request is completed // pRequest->RELEASE(FXREQUEST_STATE_TAG); goto Error; } else { // // On success, can not touch the request since it // may have already been completed // } return status; Forward: // // Cannot send-and-forget a request with a formatted IO context. // if (pRequest->HasContext()) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Cannot send-and-forget WDFREQUEST 0x%p with formatted IO" " context for filter WDFDEVICE 0x%p, %!STATUS!", pRequest->GetObjectHandle(), Device->GetHandle(), status ); FxVerifierDbgBreakPoint(FxDriverGlobals); goto Error; } // // This will skip the current stack location and perform // early dispose on the request. // pRequest->PreProcessSendAndForget(); (VOID)Irp->CallDriver(Device->GetAttachedDevice()); // // This will delete the request and free the memory back // to the device lookaside list. // pRequest->PostProcessSendAndForget(); // // Return a success status in this code path even if the previous call // to send the request to the lower driver failed. The status code returned // by this function should reflect the status of enqueuing the request and // not the status returned by the lower driver. // return STATUS_SUCCESS; Error: // // If not successful, we must set the original verifier flags. // VerifyEnqueueRequestRestoreFlags(FxDriverGlobals, pRequest, origVerifierFlags); return status; }
FORCEINLINE _Must_inspect_result_ NTSTATUS __fastcall FxPkgIo::DispatchStep1( __inout MdIrp Irp, __in WDFCONTEXT DispatchContext ) /*++ Routine Description: Checks for any registered dynamic dispatch callbacks that handles this type of request, else selects the default queue based on the IRP's major code. Arguments: Irp - WDM request. DispatchContext - Is the next FxIrpDynamicDispatchInfo element. Return Value: Irp's status. --*/ { NTSTATUS status; FxIrp fxIrp(Irp); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); // // Look for I/O dynamic dispatch callbacks. // if ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead) { int index; index = FxIrpDynamicDispatchInfo::Mj2Index(fxIrp.GetMajorFunction()); // // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., request cannot // IRP type in its callback. // if (index >= (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "Driver cannot change the IRP type in its dispatch " "callback Irp 0x%p, %!IRPMJ!, IRP_MN %x, Device 0x%p, " "%!STATUS!", Irp, fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), m_Device->GetHandle(), status); FxVerifierDbgBreakPoint(GetDriverGlobals()); goto CompleteIrp; } // // Verifier checks. // status = VerifyDispatchContext(GetDriverGlobals(), DispatchContext); if( !NT_SUCCESS(status)) { goto CompleteIrp; } do { FxIrpDynamicDispatchInfo* info; info = CONTAINING_RECORD(DispatchContext, FxIrpDynamicDispatchInfo, ListEntry); // // Advance to next node. // DispatchContext = (WDFCONTEXT)(((PLIST_ENTRY)DispatchContext)->Flink); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() == IRP_MJ_READ || fxIrp.GetMajorFunction() == IRP_MJ_WRITE || fxIrp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || fxIrp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); // // If registered, invoke dispatch callback for this major function. // ASSERT(index < (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax); if (NULL != info->Dispatch[index].EvtDeviceDynamicDispatch) { return info->Dispatch[index].EvtDeviceDynamicDispatch( m_Device->GetHandle(), fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), fxIrp.GetParameterIoctlCode(), info->Dispatch[index].DriverContext, reinterpret_cast<PIRP> (fxIrp.GetIrp()), (WDFCONTEXT)((ULONG_PTR)DispatchContext | FX_IN_DISPATCH_CALLBACK) ); } } while ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead); } // // Only now push these local variables on the stack, this is to keep the // stack from growing unnecessarily in the dynamic dispatch path above. // FxIoQueue* queue; FxIoInCallerContext* ioInCallerCtx; // // Get the queue from the dispatch-table // queue = m_DispatchTable[fxIrp.GetMajorFunction()]; if (queue == NULL) { ioInCallerCtx = GetIoInCallerContextCallback(NULL); if (ioInCallerCtx->m_Method == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, failing IRP 0x%p," " %!STATUS!", m_Device->GetHandle(), Irp, status); goto CompleteIrp; } } else { ioInCallerCtx = GetIoInCallerContextCallback(queue->GetCxDeviceInfo()); } // // If the driver is filter and queue is a default-queue then before // calling the queue, we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. // This is to cover the scenario where the driver has registered only // type specific handler and expect the framework to auto-forward other // requests. // if (m_Filter && ioInCallerCtx->m_Method == NULL && queue == m_DefaultQueue && queue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)fxIrp.GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } // // Finally queue request. // return DispatchStep2(Irp, ioInCallerCtx, queue); Forward: fxIrp.SkipCurrentIrpStackLocation(); return fxIrp.CallDriver(m_Device->GetAttachedDevice()); CompleteIrp: fxIrp.SetStatus(status); fxIrp.SetInformation(0); fxIrp.CompleteRequest(IO_NO_INCREMENT); return status; }
_Must_inspect_result_ NTSTATUS FxPkgIo::ResumeProcessingForPower() /*++ Routine Description: Resumes all PowerManaged queues for automatic I/O processing due to a power event that allows I/O to resume. Non-PowerManaged queues are left alone. Arguments: Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Power resume all queues of WDFDEVICE 0x%p", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); // // Change the state so that new queues created while we // are resuming the existing queues can be in a powered-on state. // m_PowerStateOn = TRUE; // // Change the accepting state so that new queues created while we // are resuming the existing queues can be accept request. // m_QueuesAreShuttingDown = FALSE; Unlock(irql); // // We will power-up the queues in two steps. First we will resume // the power of all the queues and then we will start dispatching I/Os. // This is to avoid a queue being powered up at the begining of the list // trying to forward a request to another queue lower in the list that's // not powered up yet. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResumeProcessingForPower(); } for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOn(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }
_Must_inspect_result_ NTSTATUS FxPkgIo::StopProcessingForPower( __in FxIoStopProcessingForPowerAction Action ) /*++ Routine Description: Stops all PowerManaged queues automatic I/O processing due to a power event that requires I/O to stop. This is called on a PASSIVE_LEVEL thread that can block until I/O has been stopped, or completed/cancelled. Arguments: Action - FxIoStopProcessingForPowerHold: the function returns when the driver has acknowledged that it has stopped all I/O processing, but may have outstanding "in-flight" requests that have not been completed. FxIoStopProcessingForPowerPurgeManaged: the function returns when all requests from a power managed queue have been completed and/or cancelled., and there are no more in-flight requests. FxIoStopProcessingForPowerPurgeNonManaged: the function returns when all requests from a non-power managed queue have been completed and/or cancelled., and there are no more in-flight requests. Only called during device-remove. Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Perform %!FxIoStopProcessingForPowerAction! for all queues of " "WDFDEVICE 0x%p", Action, m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); // // Device is moving into low power state. So any new queues // created after this point would start off as powered off. // m_PowerStateOn = FALSE; // // If queues are shutting down, any new queue created after // this point would not accept any requests. // switch(Action) { case FxIoStopProcessingForPowerPurgeManaged: case FxIoStopProcessingForPowerPurgeNonManaged: m_QueuesAreShuttingDown = TRUE; break; } GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOff); Unlock(irql); // // If the power action is hold then first change the state of all the queues // to PowerStartTransition. This will prevent the queues from dispatching // new requests before we start asking each queue to stop processing // inflight requests. // if(Action == FxIoStopProcessingForPowerHold) { // // Walk the list without popping entries because we need to scan // the list again. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOff(); } } // // Ask the queues to stop processing inflight requests. // for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StopProcessingForPower(Action); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }