VOID
FxInterrupt::ReportInactive(
    _In_ BOOLEAN Internal
    )
{
    IO_REPORT_INTERRUPT_ACTIVE_STATE_PARAMETERS parameters;
    FxPkgPnp* fxPkgPnp;

    fxPkgPnp = m_Device->m_PkgPnp;

    if (Internal == FALSE) {
        //
        // if the interrupt is not connected, you can't report active or inactive
        //
        if(m_Connected == FALSE || m_Interrupt == NULL) {
            DoTraceLevelMessage(
                GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
                "Driver is reporting WDFINTERRUPT %p as being inactive even though"
                " it is not connected.",  GetHandle());
            FxVerifierDbgBreakPoint(GetDriverGlobals());
            return;
        }
        
        if (fxPkgPnp->m_IoReportInterruptInactive == NULL) {
            DoTraceLevelMessage(
                GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
                "Driver is calling DDI WdfInterruptReportInactive() on an OS that "
                "doesn't support the DDI.");
            FxVerifierDbgBreakPoint(GetDriverGlobals());
            return;
        }
    }
    
    //
    // No need to report Inactive if interrupt is already Inactive
    //
    if (m_Active == FALSE) {
        return;
    }

    RtlZeroMemory(&parameters, sizeof(parameters));

    if (FxIsProcessorGroupSupported()) {
        parameters.Version = CONNECT_FULLY_SPECIFIED_GROUP;
    }
    else {
        parameters.Version = CONNECT_FULLY_SPECIFIED;
    }

    parameters.ConnectionContext.InterruptObject = m_Interrupt;

    fxPkgPnp->m_IoReportInterruptInactive(&parameters);
    m_Active = FALSE;

    return;
}
Esempio n. 2
0
VOID
FX_VF_FUNCTION(VerifyWdfDeviceWdmDispatchIrp) (
    _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
    _In_ PWDF_DRIVER_GLOBALS DriverGlobals,
    _In_ FxDevice* device, 
    _In_ WDFCONTEXT  DispatchContext
    )
{    
    UNREFERENCED_PARAMETER(FxDriverGlobals);
    FxDriver*   driver;
    BOOLEAN     ctxValid;
    PLIST_ENTRY next;
    NTSTATUS    status;

    PAGED_CODE_LOCKED();

    status = STATUS_SUCCESS;
    driver = GetFxDriverGlobals(DriverGlobals)->Driver;
    ctxValid = (PLIST_ENTRY)DispatchContext == 
                &device->m_PreprocessInfoListHead ? TRUE : FALSE;
    //
    // Driver should be a cx.
    //
    if (device->IsCxDriverInIoPath(driver) == FALSE) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(
                device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
                "This API can only be called by wdf extension driver "
                "from its pre-process IRP callback, %!STATUS!",
                status);
        FxVerifierDbgBreakPoint(device->GetDriverGlobals());
    }
    
    //
    // Validate DispatchContext.
    //

    for (next = device->m_PreprocessInfoListHead.Flink;
         next != &device->m_PreprocessInfoListHead;
         next = next->Flink) {
        if ((PLIST_ENTRY)DispatchContext == next) {
            ctxValid = TRUE;
            break;
        }
    }

    if (FALSE == ctxValid) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
                device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
                "DispatchContext 0x%p is invalid, %!STATUS!",
                DispatchContext, status);
        FxVerifierDbgBreakPoint(device->GetDriverGlobals());
    }
}
VOID
FxWorkItem::FlushAndWait()
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;

    pFxDriverGlobals = GetDriverGlobals();

    if (m_WorkItemThread == Mx::MxGetCurrentThread()) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                        "Calling WdfWorkItemFlush from within the WDFWORKITEM "
                        "%p callback will lead to deadlock, PRKTHREAD %p", 
                        GetHandle(), m_WorkItemThread);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return;
    }

    //
    // Wait for any outstanding workitem to complete.
    // The event is only set upon return from the callback
    // into the driver *and* the driver did not re-queue
    // the workitem. See similar comment in WorkItemHandler().
    //
    WaitForSignal();
    return;
}
Esempio n. 4
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;
}
VOID
WDFEXPORT(WdfCollectionRemove)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCOLLECTION Collection,
    __in
    WDFOBJECT Item
    )
{
    DDI_ENTRY();

    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCollection *pCollection;
    FxCollectionEntry *pEntry;
    FxObject* pObject;
    NTSTATUS status;
    KIRQL irql;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   Collection,
                                   FX_TYPE_COLLECTION,
                                   (PVOID*) &pCollection,
                                   &pFxDriverGlobals);

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         Item,
                         FX_TYPE_OBJECT,
                         (PVOID*) &pObject);

    pCollection->Lock(&irql);

    pEntry = pCollection->FindEntryByObject(pObject);

    if (pEntry != NULL) {
        pCollection->CleanupEntry(pEntry);
        status = STATUS_SUCCESS;
    }
    else {
        pObject = NULL;
        status = STATUS_NOT_FOUND;
    }

    pCollection->Unlock(irql);

    if (pObject != NULL) {
        pCollection->CleanupEntryObject(pObject);
    }

    if (!NT_SUCCESS(status)) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
                            "WDFOBJECT %p not in WDFCOLLECTION %p, %!STATUS!",
                            Item, Collection, status);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
}
Esempio n. 6
0
NTSTATUS
WDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDEVICE Device,
    __in
    MdIrp Irp
    )
{
    FxDevice            *device;
    PFX_DRIVER_GLOBALS  fxDriverGlobals;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   Device,
                                   FX_TYPE_DEVICE,
                                   (PVOID*) &device,
                                   &fxDriverGlobals);

    FxPointerNotNull(fxDriverGlobals, Irp);
    
    //
    // Verifier checks. 
    // This API can only be called by the client driver, Cx must call 
    // WdfDeviceWdmDispatchIrp from its preprocess callback.
    // Also, Cx must register for a Preprocessor routine using 
    // WdfCxDeviceInitAssignWdmIrpPreprocessCallback.
    //
    if (fxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
        if (device->IsCxInIoPath()) {
            FxDriver* driver = GetFxDriverGlobals(DriverGlobals)->Driver;
            
            if (IsListEmpty(&device->m_PreprocessInfoListHead) ||
                device->IsCxDriverInIoPath(driver)) {

                DoTraceLevelMessage(
                        fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                        "This API can only be called by client driver from its "
                        "pre-process IRP callback, STATUS_INVALID_DEVICE_REQUEST");
                FxVerifierDbgBreakPoint(fxDriverGlobals);
            }
        }
    }

    //
    // OK, ready to dispatch IRP.
    //
    return device->DispatchPreprocessedIrp(
                        Irp, 
                        device->m_PreprocessInfoListHead.Flink->Flink);
}
VOID
FxWorkItem::Enqueue(
    VOID
    )
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    KIRQL irql;
    BOOLEAN enqueue;

    pFxDriverGlobals = GetDriverGlobals();
    enqueue = FALSE;

    Lock(&irql);

    if (m_Enqueued) {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE,
            "Previously queued WDFWORKITEM 0x%p is already pending. "
            "Ignoring the request to queue again", GetHandle());
    }
    else if (m_RunningDown) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                "WDFWORKITEM 0x%p is already deleted", GetHandle());
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
    else {
        m_WorkItemCompleted.Clear();

        m_Enqueued = TRUE;

        //
        // We are going to enqueue the work item. Reference this FxWorkItem 
        // object and Globals while they are outstanding.
        // These will be released when the workitem completes.
        //
        ADDREF(WorkItemThunk);
        pFxDriverGlobals->ADDREF(WorkItemThunk);

        enqueue = TRUE;
    }

    Unlock(irql);

    if (enqueue) {
        m_WorkItem. Enqueue(FxWorkItem::WorkItemThunk, this);
    }

    return;
}
FxDpc::~FxDpc()
{
    //
    // If this hits, its because someone destroyed the DPC by
    // removing too many references by mistake without calling WdfObjectDelete
    //
    if (m_Object != NULL) {
        DoTraceLevelMessage(
            GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "Destroy WDFDPC %p destroyed without calling WdfObjectDelete, or by"
            " Framework processing DeviceRemove.  Possible reference count "
            "problem?", GetObjectHandleUnchecked());
        FxVerifierDbgBreakPoint(GetDriverGlobals());
    }
}
Esempio n. 9
0
FORCEINLINE
static
NTSTATUS
FxValiateCx(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in PFX_DRIVER_GLOBALS CxDriverGlobals
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    
    if (FxIsClassExtension(FxDriverGlobals, CxDriverGlobals) == FALSE) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "This function can only be called by a WDF "
                            "extension driver, Driver 0x%p, %!STATUS!",
                            CxDriverGlobals->Public.Driver, status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
    }

    return status;
}
Esempio n. 10
0
_Must_inspect_result_
NTSTATUS
FX_VF_METHOD(FxPkgIo, VerifyDispatchContext) (
    _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
    _In_ WDFCONTEXT DispatchContext
)
{
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN ctxValid;
    PLIST_ENTRY next;

    PAGED_CODE_LOCKED();

    //
    // Make sure context is valid.
    //
    ctxValid = (PLIST_ENTRY)DispatchContext ==
               &m_DynamicDispatchInfoListHead ?
               TRUE : FALSE;

    for (next = m_DynamicDispatchInfoListHead.Flink;
            next != &m_DynamicDispatchInfoListHead;
            next = next->Flink) {
        if ((PLIST_ENTRY)DispatchContext == next) {
            ctxValid = TRUE;
            break;
        }
    }

    if (FALSE == ctxValid) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
            FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
            "DispatchContext 0x%p is invalid, %!STATUS!",
            DispatchContext, status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
    }

    return status;
}
Esempio n. 11
0
_Must_inspect_result_
NTSTATUS
FxPkgIo::SetFilter(
    __in BOOLEAN Value
)
{
    PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();

    if (m_DefaultQueue != NULL) {
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                            "I/O Package already has a default queue. "
                            "SetFilter must be called before creating "
                            "a default queue %!STATUS!",
                            STATUS_INVALID_DEVICE_REQUEST);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    m_Filter = Value;

    return STATUS_SUCCESS;
}
FxWorkItem::~FxWorkItem(
    VOID
    )
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;

    pFxDriverGlobals = GetDriverGlobals();

    //
    // If this hits, it's because someone destroyed the WORKITEM by
    // removing too many references by mistake without calling WdfObjectDelete
    //
    if (m_RunningDown == FALSE && m_Callback != NULL) {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "WDFWORKITEM %p destroyed without calling WdfObjectDelete, or by "
            "Framework processing DeviceRemove.  Possible reference count "
            "problem?", GetObjectHandleUnchecked());
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }

    // Release our parent object reference
    if (m_Object != NULL) {
        m_Object->RELEASE(this);
        m_Object = NULL;
    }

    // Free the workitem
    if (m_WorkItem.GetWorkItem() != NULL) {
        m_WorkItem.Free();
        //m_WorkItem = NULL;
    }

    ASSERT(m_Enqueued == FALSE);
    ASSERT(m_WorkItemRunningCount == 0L);

    return;
}
Esempio n. 13
0
VOID
WDFEXPORT(WdfDeviceSetSpecialFileSupport)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDEVICE Device,
    __in
    WDF_SPECIAL_FILE_TYPE FileType,
    __in
    BOOLEAN Supported
    )
{
    FxDevice* pDevice;
    PFX_DRIVER_GLOBALS pFxDriverGlobals;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   Device,
                                   FX_TYPE_DEVICE,
                                   (PVOID *) &pDevice,
                                   &pFxDriverGlobals);

    if (FileType < WdfSpecialFilePaging  || FileType >= WdfSpecialFileMax) {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "WDFDEVICE 0x%p FileType %d specified is not in valid range",
            Device, FileType);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return;
    }

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         Device,
                         FX_TYPE_DEVICE,
                         (PVOID*) &pDevice);

    pDevice->m_PkgPnp->SetSpecialFileSupport(FileType, Supported);
}
Esempio n. 14
0
_Must_inspect_result_
NTSTATUS
FX_VF_FUNCTION(VerifyWdfDeviceWdmDispatchIrpToIoQueue) (
    _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
    _In_ FxDevice* device,
    _In_ MdIrp Irp,
    _In_ FxIoQueue* queue,
    _In_ ULONG Flags
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

    PAGED_CODE_LOCKED();

    DoTraceLevelMessage(
        FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
        "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p",
        device->GetHandle(), device->GetDeviceObject(),
        stack->MajorFunction, stack->MinorFunction, Irp);

    //
    // Validate Flags.
    //
    if (Flags & ~FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
                FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                "Flags 0x%x are invalid, %!STATUS!",
                Flags, status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        goto Done;
    }
    
    //
    // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., the I/O request set.
    //
    if (device->GetDispatchPackage(stack->MajorFunction) != device->m_PkgIo) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
                FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                "Only Read/Write/Control/Internal-Control IRPs can be "
                "forwarded to I/O Queue 0x%p, Irp 0x%p, %!IRPMJ!, "
                "IRP_MN %x, Device 0x%p, %!STATUS!",
                 queue->GetHandle(), Irp, stack->MajorFunction, stack->MinorFunction, 
                 device->GetObjectHandle(), status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        goto Done;
    }

    //
    // Make sure queue can handle the request. 
    //
    if (FALSE == queue->IsIoEventHandlerRegistered(
                            (WDF_REQUEST_TYPE)stack->MajorFunction)) {
            
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
                FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                "I/O Queue 0x%p cannot handle Irp 0x%p, %!IRPMJ!, "
                "IRP_MN %x, Device 0x%p, %!STATUS!",
                 queue->GetHandle(), Irp, stack->MajorFunction, stack->MinorFunction, 
                 device->GetObjectHandle(), status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        goto Done;
    }
                            
    if (device->m_ParentDevice == queue->GetDevice()) {
        //
        // Send to parent device's queue validation.
        //
        if (device->m_ParentDevice == NULL) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                    FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                    "No parent device for Device 0x%p, %!STATUS!",
                     device->GetObjectHandle(), status);
            FxVerifierDbgBreakPoint(FxDriverGlobals);
            goto Done;
        }

        //
        // Make sure the child device is a PDO 
        //
        ASSERT(device->IsPdo());            

        //
        // Check if the WdfPdoInitSetForwardRequestToParent was called to 
        // increase the StackSize of the child Device  to include the stack
        // size of the parent Device
        //
        if (device->IsPnp() && 
            device->GetPdoPkg()->m_AllowForwardRequestToParent == FALSE) {
            status = STATUS_INVALID_DEVICE_REQUEST;
            DoTraceLevelMessage(
                    FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                    "WdfPdoInitSetForwardRequestToParent not called on "
                    "Device 0x%p, %!STATUS!", 
                    device->GetObjectHandle(), status);            
            FxVerifierDbgBreakPoint(FxDriverGlobals);
            goto Done;
        }
    }
    else {
        //
        // Send to current device's queue validation.
        //
        if (device != queue->GetDevice()) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                    FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                    "Cannot forward a request to "
                    "a different Device 0x%p, %!STATUS!",
                    queue->GetDevice()->GetObjectHandle(), status);
            FxVerifierDbgBreakPoint(FxDriverGlobals);
            goto Done;
        }
    }
    
Done:    
    return status;
}
//
// Destroy (dereference) the WDFFILEOBJECT related to the
// WDM PFILE_OBJECT according to its FileObjectClass.
//
VOID
FxFileObject::_DestroyFileObject(
    __in FxDevice*                   pDevice,
    __in WDF_FILEOBJECT_CLASS        FileObjectClass,
    __in_opt MdFileObject            pWdmFileObject
    )
{
    FxFileObject* pfo = NULL;
    PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
    WDF_FILEOBJECT_CLASS normalizedFileClass;
    
    //
    // Close does require a WDM file obj based on the normalized file obj 
    // class value.
    //
    normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);

    if( normalizedFileClass == WdfFileObjectNotRequired ) {
        return;
    }

    //
    // Driver has specified file object support, and we
    // allocated one at Create, so they must pass one
    // to close, otherwise it's an error and we will leak
    // the file object.
    //
    MxFileObject wdmFileObject(pWdmFileObject);
    if( pWdmFileObject == NULL && 
        normalizedFileClass != WdfFileObjectWdfCannotUseFsContexts) {

        //
        // It's likely that IRP_MJ_CREATE had NULL for the Wdm FileObject as well.
        //
        // If a driver passes != NULL for Wdm FileObject to create, and NULL to
        // this routine, a WDF FxFileObject object leak will occur, which will
        // be reported at driver unload.
        //
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
           "PFILE_OBJECT in close IRP is NULL, *Possible Leak of FxFileObject*\n");

        FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());

        return;
    }
    else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext();
        wdmFileObject.SetFsContext(NULL);
        
    }
    else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
        wdmFileObject.SetFsContext2(NULL);
    }
    else {
        NTSTATUS status;
        //
        // We must find the associated FxFileObject from the list
        // on the device
        //
        status = FxFileObject::_GetFileObjectFromWdm(
                          pDevice,
                          WdfFileObjectWdfCannotUseFsContexts,
                          pWdmFileObject,
                          &pfo
                          );
        
        //
        // We should find it, unless a different one was passed to IRP_MJ_CLOSE
        // than to IRP_MJ_CREATE, which is an error.
        //
        if (NT_SUCCESS(status) == FALSE || pfo == NULL) {
            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Could not find WDFFILEOBJECT for PFILE_OBJECT 0x%p",
                                pWdmFileObject);

            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Did a different PFILE_OBJECT get passed to "
                            "IRP_MJ_CLOSE than did to IRP_MJ_CREATE?");
            FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
        }
    }

    if( pfo != NULL ) {
        KIRQL irql;

        //
        // Remove it from the list of FxFileObjects on the FxDevice
        //
        pDevice->Lock(&irql);
        RemoveEntryList(&pfo->m_Link);
        pDevice->Unlock(irql);

        // Delete the file object
        pfo->DeleteObject();
    }

    return;
}
Esempio n. 16
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;
}
Esempio n. 17
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;
}
VOID
FxPowerIdleMachine::IoDecrement(
    __in_opt PVOID Tag,
    __in_opt LONG Line,
    __in_opt PSTR File
    )
/*++

Routine Description:
    Public function which allows the caller decrement the pending io count on
    this state machine.  If the count goes to zero and idle is enabled, then
    the timer is started.

Arguments:
    None

Return Value:
    None

  --*/
{
    KIRQL irql;
    FxPkgPnp* pPkgPnp;
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    ULONG count;

    pPkgPnp = GetPnpPkg(this);
    pFxDriverGlobals = pPkgPnp->GetDriverGlobals();

    m_Lock.Acquire(&irql);

    if (m_IoCount == 0) {
        //
        // We can get here for the following reasons:
        // 1. Driver called WdfDevicveStopIdle/WdfDeviceResumeIdle in a mismatched
        //    manner. This is a driver bug.
        // 2. Framework did power deref without a corresponding power ref.
        //    This would be a framework bug. 
        //
        // We will break into debugger if verifier is turned on. This will allow
        // developers to catch this problem during develeopment.
        // We limit this break to version 1.11+ because otherwise older drivers 
        // may hit this, and if they cannot be fixed for some reason, then 
        // verifier would need to be turned off to avoid the break which is not 
        // desirable. 
        // 
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
            "WDFDEVICE 0x%p !devobj 0x%p The device is being power-dereferenced"
            " without a matching power-reference. This could occur if driver"
            " incorrectly calls WdfDeviceResumeIdle without a matching call to"
            " WdfDeviceStopIdle.",
            pPkgPnp->GetDevice()->GetHandle(),
            pPkgPnp->GetDevice()->GetDeviceObject());
        
        if (pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
           FxVerifierDbgBreakPoint(pFxDriverGlobals);
        }
    }

    ASSERT(m_IoCount > 0);
    count = --m_IoCount;
    ProcessEventLocked(PowerIdleEventIoDecrement);
    m_Lock.Release(irql);

    if (m_TagTracker != NULL) {
        m_TagTracker->UpdateTagHistory(Tag, Line, File, TagRelease, count);
    }
}
Esempio n. 19
0
NTSTATUS
WDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDEVICE Device,
    __in
    PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings
    )
/*++

Routine Description:
    The DDI is invoked by KMDF client drivers for single-component devices to 
    specify their power framework settings to KMDF. KMDF uses these settings on 
    Win8+ when registering with the power framework. 
    
    On Win7 and older operating systems the power framework is not available, so
    KMDF does nothing.

Arguments:

    Device - Handle to the framework device object for which power framework 
      settings are being specified.

    PowerFrameworkSettings - Pointer to a WDF_POWER_FRAMEWORK_SETTINGS structure
      that contains the client driver's power framework settings.             

Return Value:
    An NTSTATUS value that denotes success or failure of the DDI

--*/
{
    NTSTATUS status;
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxDevice *pDevice;

    //
    // Validate the Device object handle and get its FxDevice. Also get the 
    // driver globals pointer.
    //
    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   Device,
                                   FX_TYPE_DEVICE,
                                   (PVOID *) &pDevice,
                                   &pFxDriverGlobals);
                         
    FxPointerNotNull(pFxDriverGlobals, PowerFrameworkSettings);

    //
    // Only power policy owners should call this DDI
    //
    if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "WDFDEVICE 0x%p is not the power policy owner, so the caller cannot"
            " assign power framework settings %!STATUS!", Device, status);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return status;
    }

    //
    // Validate the Settings parameter
    //
    if (PowerFrameworkSettings->Size != sizeof(WDF_POWER_FRAMEWORK_SETTINGS)) {
        status = STATUS_INFO_LENGTH_MISMATCH;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "WDFDEVICE 0x%p Expected PowerFrameworkSettings size %d, actual %d,"
            " %!STATUS!",
            Device,
            sizeof(WDF_POWER_FRAMEWORK_SETTINGS), 
            PowerFrameworkSettings->Size,
            status);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return status;
    }

    //
    // If settings for component 0 are specified, make sure it contains at least
    // one F-state.
    //
    if (NULL != PowerFrameworkSettings->Component) {

        if (0 == PowerFrameworkSettings->Component->IdleStateCount) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                "WDFDEVICE 0x%p Component settings are specified but "
                "IdleStateCount is 0. %!STATUS!", Device, status);
            FxVerifierDbgBreakPoint(pFxDriverGlobals);
            return status;
        }

        if (NULL == PowerFrameworkSettings->Component->IdleStates) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                "WDFDEVICE 0x%p Component settings are specified but IdleStates"
                " is NULL. %!STATUS!", Device, status);
            FxVerifierDbgBreakPoint(pFxDriverGlobals);
            return status;
        }
    }

    //
    // Assign the driver's settings
    //
    status = pDevice->m_PkgPnp->AssignPowerFrameworkSettings(
                                            PowerFrameworkSettings);
    
    return status;
}
Esempio n. 20
0
_Must_inspect_result_
NTSTATUS
FxPkgIo::ConfigureForwarding(
    __inout FxIoQueue* TargetQueue,
    __in    WDF_REQUEST_TYPE RequestType
)
{
    PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
    KIRQL irql;
    NTSTATUS status;

    ASSERT(RequestType <= IRP_MJ_MAXIMUM_FUNCTION);

    if(TargetQueue->IsIoEventHandlerRegistered(RequestType) == FALSE) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                            "Must have EvtIoDefault or %!WDF_REQUEST_TYPE! "
                            "specific dispatch event registered for "
                            "WDFQUEUE 0x%p, %!STATUS!", RequestType,
                            TargetQueue->GetObjectHandle(),
                            status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        return status;
    }

    // Lock IoPackage data structure

    Lock(&irql);

    if (TargetQueue == m_DefaultQueue) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                            "Default WDFQUEUE 0x%p cannot be configured to "
                            "dispatch specific type of request, %!STATUS!",
                            TargetQueue->GetObjectHandle(),
                            status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        Unlock(irql);
        return status;
    }

    // Error if already has an entry
    if (m_DispatchTable[RequestType] != NULL &&
            m_DispatchTable[RequestType] != m_DefaultQueue) {
        status = STATUS_WDF_BUSY;
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
                            "%!WDF_REQUEST_TYPE! is already configured for"
                            "WDFQUEUE 0x%p, %!STATUS!", RequestType,
                            TargetQueue->GetObjectHandle(),
                            status);
        FxVerifierDbgBreakPoint(FxDriverGlobals);
        Unlock(irql);
        return status;
    }

    //
    // We don't take an extra reference count since we already
    // have one from our associated list (DriverQueues)
    //
    m_DispatchTable[RequestType] = TargetQueue;

    //
    // Queues configured to auto-dispatch requests cannot be deleted
    //
    TargetQueue->MarkNoDeleteDDI();

    Unlock(irql);

    return STATUS_SUCCESS;
}
NTSTATUS
WDFEXPORT(WdfDmaTransactionInitializeUsingRequest)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDMATRANSACTION DmaTransaction,
    __in
    WDFREQUEST Request,
    __in
    PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction,
    __in
    WDF_DMA_DIRECTION DmaDirection
    )
{
    NTSTATUS status;
    FxDmaTransactionBase* pDmaTrans;
    FxRequest* pReqObj;
    MDL* mdl = NULL;
    PIO_STACK_LOCATION stack;
    ULONG reqLength;
    PFX_DRIVER_GLOBALS  pFxDriverGlobals;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   DmaTransaction,
                                   FX_TYPE_DMA_TRANSACTION,
                                   (PVOID *) &pDmaTrans,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction);

    if (DmaDirection != WdfDmaDirectionReadFromDevice &&
        DmaDirection != WdfDmaDirectionWriteToDevice) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
            "Initialization of WDFDMATRANSACTION 0x%p using WDFREQUEST %p, "
            "DmaDirection 0x%x is an invalid value, %!STATUS!",
            DmaTransaction, Request, DmaDirection, status);
        return status;
    }

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         Request,
                         FX_TYPE_REQUEST,
                         (PVOID *) &pReqObj);

    reqLength = 0;

    stack = pReqObj->GetFxIrp()->GetCurrentIrpStackLocation();

    //
    // Get the MDL and Length from the request.
    //
    switch (stack->MajorFunction) {

    case IRP_MJ_READ:

        if (DmaDirection != WdfDmaDirectionReadFromDevice) {
            status = STATUS_INVALID_DEVICE_REQUEST;

            DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                "0x%p doesn't match with the WDFREQUEST 0x%p type "
                                "%!WDF_REQUEST_TYPE! %!STATUS!",
                                DmaDirection, DmaTransaction, Request,
                                stack->MajorFunction, status);

            return status;
        }

        reqLength = stack->Parameters.Read.Length;

        status = pReqObj->GetMdl(&mdl);
        break;

    case IRP_MJ_WRITE:

        if (DmaDirection != WdfDmaDirectionWriteToDevice) {
            status = STATUS_INVALID_DEVICE_REQUEST;

            DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                "0x%p doesn't match with the WDFREQUEST 0x%p type "
                                "%!WDF_REQUEST_TYPE! %!STATUS!",
                                DmaDirection, DmaTransaction, Request,
                                stack->MajorFunction, status);

            return status;
        }

        reqLength = stack->Parameters.Write.Length;

        status = pReqObj->GetMdl(&mdl);
        break;

    case IRP_MJ_DEVICE_CONTROL:
    case IRP_MJ_INTERNAL_DEVICE_CONTROL:

        switch (METHOD_FROM_CTL_CODE(stack->Parameters.DeviceIoControl.IoControlCode)) {
            case METHOD_BUFFERED:

                if (DmaDirection == WdfDmaDirectionWriteToDevice) {
                    reqLength = stack->Parameters.DeviceIoControl.InputBufferLength;
                } else {
                    reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
                }

                //
                // In this case both input buffer and output buffer map
                // to the same MDL and it's probed for read & write access.
                // So it's okay for DMA transfer in either direction.
                //
                status = pReqObj->GetMdl(&mdl);
                break;

            case METHOD_IN_DIRECT:
                //
                // For this type, the output buffer is probed for read access.
                // So the direction of DMA transfer is WdfDmaDirectionWriteToDevice.
                //
                if (DmaDirection != WdfDmaDirectionWriteToDevice) {

                    status = STATUS_INVALID_DEVICE_REQUEST;

                    DoTraceLevelMessage(pFxDriverGlobals,
                                        TRACE_LEVEL_ERROR, TRACINGDMA,
                                        "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                        "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
                                        "METHOD_IN_DIRECT %!STATUS!",
                                        DmaDirection, DmaTransaction, Request, status);
                    return status;
                }

                reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

                status = pReqObj->GetDeviceControlOutputMdl(&mdl);

                break;

            case METHOD_OUT_DIRECT:
                //
                // For this type, the output buffer is probed for write access.
                // So the direction of DMA transfer is WdfDmaDirectionReadFromDevice.
                //
                if (DmaDirection != WdfDmaDirectionReadFromDevice) {

                    status = STATUS_INVALID_DEVICE_REQUEST;

                    DoTraceLevelMessage(pFxDriverGlobals,
                                        TRACE_LEVEL_ERROR, TRACINGDMA,
                                        "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                        "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
                                        "METHOD_OUT_DIRECT %!STATUS!",
                                        DmaDirection, DmaTransaction, Request, status);

                    return status;
                }

                reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

                status = pReqObj->GetDeviceControlOutputMdl(&mdl);

                break;
            default:

                status = STATUS_INVALID_DEVICE_REQUEST;

                DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                    "Invalid ioctl code in WDFREQUEST 0x%p %!STATUS!",
                                    Request, status);

                FxVerifierDbgBreakPoint(pFxDriverGlobals);
                break;

        }// End of switch(ioctType)
        break;

    default:
        status = STATUS_INVALID_DEVICE_REQUEST;
        break;

    }

    if (!NT_SUCCESS(status)) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                            "Couldn't retrieve mdl from WDFREQUEST 0x%p for "
                            "WDFTRANSACTION 0x%p %!STATUS!",
                            Request, DmaTransaction, status);
        return status;
    }

    if (reqLength == 0) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
            "Zero length request, %!STATUS!", status);
        return status;
    }

    //
    // If the DMA enabler is packet based, make sure the virtual address and
    // the length of transfer are within bounds. Basically, we are checking
    // to see if the length of data to be transferred doesn't span multiple
    // MDLs, because packet based DMA doesn't support chained MDLs.
    //
    if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) {
        ULONG  length;

        length = MmGetMdlByteCount(mdl);

        if (reqLength > length) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                "WDFREQUEST %p transfer length (%d) is out of bounds of MDL "
                "Byte count (%d), %!STATUS!",
                Request, reqLength, length, status);

            return status;
        }
    }

    //
    // Parms appear OK, so initialize this instance.
    //
    status = pDmaTrans->Initialize(EvtProgramDmaFunction,
                                   DmaDirection,
                                   mdl,
                                   0,
                                   reqLength);

    if (!NT_SUCCESS(status)) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                            "WDFTANSACTION 0x%p initialization failed: "
                            "%!STATUS!", DmaTransaction, status);
        return status;
    }

    //
    // Set this Request in the new DmaTransaction.  The request will 
    // take a reference on this request when it starts executing.
    //
    pDmaTrans->SetRequest(pReqObj);

    return STATUS_SUCCESS;
}
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;
}
//
// Create the WDFFILEOBJECT and associate it with the WDM PFILE_OBJECT.
//
_Must_inspect_result_
NTSTATUS
FxFileObject::_CreateFileObject(
    __in FxDevice*                   pDevice,
    __in MdIrp                        Irp,
    __in WDF_FILEOBJECT_CLASS        FileObjectClass,
    __in_opt PWDF_OBJECT_ATTRIBUTES  pObjectAttributes,
    __in_opt MdFileObject            pWdmFileObject,
    __deref_out_opt FxFileObject**   pFileObject
    )
{
    NTSTATUS Status;
    FxFileObject* pfo;
    KIRQL irql;
    WDF_FILEOBJECT_CLASS normalizedFileClass;
        
    PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();

    //
    // Create does require a WDM file obj based on the normalized file obj 
    // class value.
    //
    normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
    
    //
    // No FileObject support
    //
    if( normalizedFileClass == WdfFileObjectNotRequired ) {
        if( pFileObject != NULL ) *pFileObject = NULL;
        return STATUS_SUCCESS;
    }

    //
    // If fileobject support was specified, and a NULL
    // WDM PFILE_OBJECT is supplied, then it's an error
    //
    if( pWdmFileObject == NULL ) {

        //
        // Seems like some filter driver above us sending a create without fileobject.
        // We support this only if the FileObjectClass class is set to
        // WdfFileObjectWdfCannotUseFsContexts and device is created to be
        // exclusive.
        //
        if ( normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts  && 
             pDevice->IsExclusive() ) {
            
            DO_NOTHING();

        } else {
            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
              "WdfFileObjectWdfCanUseFsContexts is specified, but the Create "
              "IRP %p doesn't have a fileObject\n",
              Irp);
            FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }

    }

    // Allocate a new FxFileObject with context
    pfo = new(pDevice->GetDriverGlobals(), pObjectAttributes)
             FxFileObject(pDevice->GetDriverGlobals(), pWdmFileObject, pDevice);

    if( pfo == NULL ) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    pfo->Initialize(Irp);

    // Assign FxDevice as the parent for the file object
    Status = pfo->Commit(pObjectAttributes, NULL, pDevice);
    if( !NT_SUCCESS(Status) ) {
        pfo->DeleteFromFailedCreate();
        return Status;
    }

    //
    // Place it on the list of FxFileObject's for this FxDevice
    //
    pDevice->Lock(&irql);
    InsertHeadList(&pDevice->m_FileObjectListHead, &pfo->m_Link);
    pDevice->Unlock(irql);

    //
    // Set file object context in mode-specific manner
    //
    pfo->SetFileObjectContext(pWdmFileObject, 
                              normalizedFileClass, 
                              Irp,
                              pDevice);
    
    // FxFileObject* to caller
    if( pFileObject != NULL ) {
        *pFileObject = pfo;
    }

    return STATUS_SUCCESS;
}
//
// Return the FxFileObject* for the given WDM PFILE_OBJECT
//
_Must_inspect_result_
NTSTATUS
FxFileObject::_GetFileObjectFromWdm(
    __in  FxDevice*                   pDevice,
    __in  WDF_FILEOBJECT_CLASS        FileObjectClass,
    __in_opt  MdFileObject            pWdmFileObject,
    __deref_out_opt FxFileObject**    ppFxFileObject
    )
{
    FxFileObject* pfo = NULL;
    PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
    WDF_FILEOBJECT_CLASS normalizedFileClass;

    //
    // Normalize file object class value.
    //
    normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);

    //
    // No FileObject support
    //
    if( normalizedFileClass == WdfFileObjectNotRequired ) {
        *ppFxFileObject = NULL;
        return STATUS_SUCCESS;
    }

    if( pWdmFileObject == NULL ) {

        //
        // Warn if an I/O request has NULL for the WDM PFILE_OBJECT
        //
        if ( pDevice->IsExclusive() &&
             normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts ) {
            //
            // We allow a NULL file object iff the device is exclusive and
            // we have to look up the WDFFILEOBJECT by PFILE_OBJECT value
            //
            DO_NOTHING();
        }
        else if ( FxIsFileObjectOptional(FileObjectClass) ) {
            //
            // Driver told us that it's able to handle this case.
            //
            *ppFxFileObject = NULL;
            return STATUS_SUCCESS;
        }
        else {
            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                                    "NULL passed for PFILE_OBJECT when FileObject "
                                    "support is requested in an I/O request");
            FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());

            return STATUS_UNSUCCESSFUL;
        }
    }

    //
    // Depending on the drivers configuration, we can quickly
    // get the FxFileObject* from FxContext, or FxContext2.
    //
    // Some drivers can not touch either of the FxContext(s), and
    // in that case we must resort to a list or hashtable.
    //
    MxFileObject wdmFileObject(pWdmFileObject);
    if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext();
    }
    else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
    }
    else {
        PLIST_ENTRY next;
        FxFileObject* f;
        KIRQL irql;

        //
        // Must look it up from the FxDevice->m_FileObjectListHead.
        //
        pfo = NULL;

        pDevice->Lock(&irql);

        next = pDevice->m_FileObjectListHead.Flink;

        if(pWdmFileObject == NULL) {
            //
            // If the pWdmFileObject is NULL then we will pass the first entry
            // in the list because the device must be exclusive and there
            // can be only one fileobject in the list.
            //
            ASSERT(IsListEmpty(&pDevice->m_FileObjectListHead) == FALSE);

            f = CONTAINING_RECORD(next, FxFileObject, m_Link);
            pfo = f;

        } else {

            while( next != &pDevice->m_FileObjectListHead ) {
                f = CONTAINING_RECORD(next, FxFileObject, m_Link);

                if( f->m_FileObject.GetFileObject()== pWdmFileObject ) {
                    pfo = f;
                    break;
                }

                next = next->Flink;
            }
        }










        if(pfo == NULL
             && pDevice->IsExclusive()
             && pDevice->GetMxDeviceObject()->GetDeviceType() == FILE_DEVICE_SERIAL_PORT
             && !IsListEmpty(&pDevice->m_FileObjectListHead)) {

            f = CONTAINING_RECORD(pDevice->m_FileObjectListHead.Flink,
                                    FxFileObject, m_Link);
            pfo = f;

            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
                            "The PFILE_OBJECT 0x%p in this request (cleanup/close) "
                            "is different from the one specified in "
                            "create request 0x%p.This is bad!", pWdmFileObject,
                            ((f != NULL) ? f->m_FileObject.GetFileObject(): NULL));
            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
                            "Since this is a serial port device, framework is "
                            "using a workaround to allow this");
        }

        pDevice->Unlock(irql);
    }

    //
    // This can happen if a different PFILE_OBJECT is passed to an I/O
    // request than was presented to IRP_MJ_CREATE
    //
    if (pfo == NULL && FxIsFileObjectOptional(FileObjectClass) == FALSE) {

        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Could not locate WDFFILEOBJECT for "
                            "PFILE_OBJECT 0x%p",pWdmFileObject);

        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Did a different PFILE_OBJECT get passed to the "
                            "request than was to IRP_MJ_CREATE?");










        if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
            FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
        }
    }

    //
    // We don't do an extra reference count since the file objects
    // lifetime is controlled by the IoMgr. When the IRP_MJ_CLOSE
    // occurs, the reference is released after the optional
    // driver event callback.
    //

    *ppFxFileObject = pfo;

    return STATUS_SUCCESS;
}