Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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;

}
Example #4
0
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;
}
Example #5
0
_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;
}
Example #6
0
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;
}
Example #8
0
_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;
}
Example #9
0
//
// 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;
}
Example #10
0
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;
}
Example #11
0
_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;
}
Example #12
0
_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;
}